Zoeken…


Eenvoudige omschrijving

Er zijn twee verschillende typen descriptoren. Gegevensdescriptors worden gedefinieerd als objecten die zowel een __get__() als een __set__() methode definiëren, terwijl niet-gegevensdescriptors alleen een __get__() methode definiëren. Dit onderscheid is belangrijk bij het overwegen van overschrijvingen en de naamruimte van het woordenboek van een instantie. Als een gegevensdescriptor en een vermelding in het woordenboek van een instantie dezelfde naam hebben, heeft de gegevensdescriptor voorrang. Als in plaats daarvan echter een niet-gegevensdescriptor en een vermelding in het woordenboek van een instantie dezelfde naam hebben, heeft de vermelding van het exemplaarwoordenboek voorrang.

Om een alleen-lezen gegevensdescriptor te maken, definieert u zowel get () als set () met de set () die een AttributeError verhoogt wanneer deze wordt aangeroepen. Het definiëren van de methode set () met een tijdelijke aanduiding voor het verhogen van uitzonderingen is voldoende om er een gegevensdescriptor van te maken.

descr.__get__(self, obj, type=None) --> value
descr.__set__(self, obj, value) --> None
descr.__delete__(self, obj) --> None

Een geïmplementeerd voorbeeld:

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

Tweerichtingsconversies

Met descriptorobjecten kunnen gerelateerde objectkenmerken automatisch reageren op wijzigingen.

Stel dat we een oscillator willen modelleren met een bepaalde frequentie (in Hertz) en periode (in seconden). Wanneer we de frequentie bijwerken, willen we dat de periode wordt bijgewerkt en wanneer we de periode bijwerken, willen we dat de frequentie wordt bijgewerkt:

 >>> 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

We kiezen een van de waarden (frequentie, in Hertz) als het 'anker', diegene die kan worden ingesteld zonder conversie en schrijven er een beschrijvingsklasse voor:

class Hertz(object):
    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        self.value = float(value)

De "andere" waarde (periode, in seconden) wordt gedefinieerd in termen van het anker. We schrijven een descriptorklasse die onze conversies uitvoert:

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 kunnen we de Oscillator-klasse schrijven:

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow