Szukaj…


Prosty deskryptor

Istnieją dwa różne typy deskryptorów. Deskryptory danych są zdefiniowane jako obiekty, które definiują zarówno __get__() i __set__() , podczas gdy deskryptory niebędące danymi definiują tylko __get__() . To rozróżnienie jest ważne przy rozważaniu przesłonięć i przestrzeni nazw słownika instancji. Jeśli deskryptor danych i pozycja w słowniku instancji mają tę samą nazwę, deskryptor danych będzie miał pierwszeństwo. Jeśli jednak deskryptor inny niż dane i pozycja w słowniku instancji mają tę samą nazwę, pozycja słownika instancji będzie miała pierwszeństwo.

Aby utworzyć deskryptor danych tylko do odczytu, zdefiniuj get () i set () za pomocą set () wywołującego AttributeError po wywołaniu. Wystarczy zdefiniować metodę set () za pomocą symbolu zastępczego zgłaszającego wyjątek, aby stała się deskryptorem danych.

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

Zaimplementowany przykład:

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

Dwukierunkowe konwersje

Obiekty deskryptorów mogą pozwalać powiązanym atrybutom obiektów automatycznie reagować na zmiany.

Załóżmy, że chcemy modelować oscylator o zadanej częstotliwości (w hercach) i kropce (w sekundach). Gdy aktualizujemy częstotliwość, chcemy, aby okres był aktualizowany, a kiedy aktualizujemy okres, chcemy, aby częstotliwość aktualizowała się:

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

Wybieramy jedną z wartości (częstotliwość, w hercach) jako „kotwicę”, tj. Tę, którą można ustawić bez konwersji, i piszemy dla niej klasę deskryptorów:

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

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

„Inna” wartość (okres, w sekundach) jest zdefiniowana w kategoriach kotwicy. Piszemy klasę deskryptora, która wykonuje nasze konwersje:

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)

Teraz możemy napisać klasę Oscillator:

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow