Дескрипторы в Python

Введение

Примеры

  • 2

    Простой дескриптор

    Есть два разных типа дескрипторов. Дескрипторы данных определяются как объекты , которые определяют одновременно __get__() и __set__() метод, тогда как дескрипторы без данных определить только __get__() метод. Это различие важно при рассмотрении переопределений и пространства имен словаря экземпляра. Если дескриптор данных и запись в словаре экземпляра имеют одно и то же имя, дескриптор данных будет иметь приоритет. Однако если вместо дескриптора не данных и записи в словаре экземпляра используется одно и то же имя, запись словаря экземпляра будет иметь приоритет.

    Для того, чтобы дескриптор данных только для чтения, определяют как получить () и установить () с множеством () поднимая AttributeError при вызове. Определение метода набора () с исключением повышающего заполнителем достаточно , чтобы сделать его дескриптор данных.

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

    Реализованный пример:

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

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

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

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

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

Синтаксис

Параметры

Примечания