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


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow