Python Language
Deskryptor
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