Двусторонние преобразования

Объекты дескриптора могут позволить атрибутам связанных объектов автоматически реагировать на изменения.

Предположим, мы хотим смоделировать генератор с заданной частотой (в герцах) и периодом (в секундах). Когда мы обновляем частоту, мы хотим, чтобы период обновлялся, и когда мы обновляем период, мы хотим, чтобы частота обновлялась:

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

 

Мы выбираем одно из значений (частота в герцах) в качестве «якоря», то есть того, которое можно установить без преобразования, и записываем для него класс дескриптора:

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

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

 

«Другое» значение (период в секундах) определяется в терминах привязки. Мы пишем класс дескриптора, который выполняет наши преобразования:

 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)

 

Теперь мы можем написать класс 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