Python Language
Descriptor
Sök…
Enkel deskriptor
Det finns två olika typer av deskriptorer. Dataskrivare definieras som objekt som definierar både en __get__()
och en __set__()
-metod, medan icke-dataskrivare bara definierar en __get__()
-metod. Denna skillnad är viktig när man överväger åsidosättningar och namnområdet i en instanss ordbok. Om en databeskrivare och en post i en instanss ordbok delar samma namn kommer dataskrivaren att ha företräde. Om istället en icke-dataskrivare och en post i en instanss ordbok delar samma namn, kommer instansordbokens post att ha företräde.
För att skapa en skrivskyddad databeskrivare, definiera både get () och set () med uppsättningen () att höja en AttributeError när den anropas. Att definiera metoden set () med undantag för att höja platshållaren är tillräckligt för att göra det till en databeskrivare.
descr.__get__(self, obj, type=None) --> value
descr.__set__(self, obj, value) --> None
descr.__delete__(self, obj) --> None
Ett implementerat exempel:
class DescPrinter(object):
"""A data descriptor that logs activity."""
_val = 7
def __get__(self, obj, objtype=None):
print('Getting ...')
return self._val
def __set__(self, obj, val):
print('Setting', val)
self._val = val
def __delete__(self, obj):
print('Deleting ...')
del self._val
class Foo():
x = DescPrinter()
i = Foo()
i.x
# Getting ...
# 7
i.x = 100
# Setting 100
i.x
# Getting ...
# 100
del i.x
# Deleting ...
i.x
# Getting ...
# 7
Tvåvägsomvandlingar
Beskrivningsobjekt kan tillåta relaterade objektattribut att reagera automatiskt på förändringar.
Anta att vi vill modellera en oscillator med en given frekvens (i Hertz) och period (i sekunder). När vi uppdaterar frekvensen vill vi att perioden ska uppdateras, och när vi uppdaterar perioden vill vi att frekvensen ska uppdateras:
>>> oscillator = Oscillator(freq=100.0) # Set frequency to 100.0 Hz
>>> oscillator.period # Period is 1 / frequency, i.e. 0.01 seconds
0.01
>>> oscillator.period = 0.02 # Set period to 0.02 seconds
>>> oscillator.freq # The frequency is automatically adjusted
50.0
>>> oscillator.freq = 200.0 # Set the frequency to 200.0 Hz
>>> oscillator.period # The period is automatically adjusted
0.005
Vi väljer ett av värdena (frekvens, i Hertz) som "ankaret", dvs det som kan ställas in utan konvertering, och skriver en beskrivningsklass för det:
class Hertz(object):
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
self.value = float(value)
Det "andra" värdet (period, i sekunder) definieras i termer av ankaret. Vi skriver en beskrivningsklass som gör våra omvandlingar:
class Second(object):
def __get__(self, instance, owner):
# When reading period, convert from frequency
return 1 / instance.freq
def __set__(self, instance, value):
# When setting period, update the frequency
instance.freq = 1 / float(value)
Nu kan vi skriva Oscillator-klassen:
class Oscillator(object):
period = Second() # Set the other value as a class attribute
def __init__(self, freq):
self.freq = Hertz() # Set the anchor value as an instance attribute
self.freq = freq # Assign the passed value - self.period will be adjusted