Почему в Python свойства имеют приоритет над атрибутами экземпляра? - PullRequest
0 голосов
/ 16 декабря 2018

В этой статье описывается, как Python ищет атрибут объекта при его выполнении o.a.Порядок приоритетов интересен - он ищет:

  1. Атрибут класса, который является дескриптором данных (чаще всего это свойство)
  2. Атрибут экземпляра
  3. Любойдругой атрибут класса

Мы можем подтвердить это с помощью приведенного ниже кода, который создает объект o с атрибутом экземпляра a, класс которого содержит свойство с тем же именем:

class C:
    def __init__(self):
        self.__dict__['a'] = 1

    @property
    def a(self):
        return 2

o = C()
print(o.a)  # Prints 2

Почему Python использует этот порядок приоритетов, а не «наивный» порядок (атрибуты экземпляра имеют приоритет над всеми атрибутами класса)?Порядок приоритетов в Python имеет существенный недостаток: он замедляет поиск атрибутов, потому что вместо простого возврата атрибута o, если он существует (общий случай), Python должен сначала найти класс o и все егосуперклассы для дескриптора данных.

В чем преимущество порядка приоритетов Python?Предположительно, это не только для описанной выше ситуации, потому что наличие переменной экземпляра и свойства с одинаковым именем является очень угловым случаем (обратите внимание на необходимость использования self.__dict__['a'] = 1 для создания атрибута экземпляра, потому что обычный self.a = 1 вызоветсвойство).

Существует ли другая ситуация, в которой "наивный" порядок поиска может вызвать проблемы?

Ответы [ 3 ]

0 голосов
/ 21 декабря 2018

Что я хочу знать, так это то, почему дескрипторы данных имеют приоритет над атрибутами экземпляра?

Если нет какого-либо метода, который имеет приоритет над обычным поиском экземпляра, как выожидать перехватить доступ к атрибуту экземпляра?Эти методы сами по себе не могут быть атрибутами экземпляра, потому что это противоречит их цели (по крайней мере, без дополнительных соглашений о них, я думаю).

Кроме краткого комментария @timgeb, я ничего не могу объяснить о дескрипторахлучше, чем официальный Descriptor How To

0 голосов
/ 21 декабря 2018

Для классов старого стиля ( PEP 252 ):

Экземпляр dict переопределяет класс dict, за исключением специальных атрибутов (таких как __dict__ и __class__), которые имеют приоритет над экземпляром dict.

Переопределение __dict__ или __class__ в экземпляре dict нарушит поиск атрибутов и приведет к тому, что экземпляр будет вести себя крайне странным образом.

В классах нового стиля Гвидо выбрал следующую реализацию поиска атрибутов для обеспечения согласованности ( PEP 252 ):

  1. Посмотрите в типе dict.Если вы найдете дескриптор данных, используйте его метод get() для получения результата.Это заботится о специальных атрибутах, таких как __dict__ и __class__.
  2. Посмотрите на экземпляр dict.Если вы найдете что-нибудь, это все.(При этом учитывается требование, что обычно экземпляр dict переопределяет класс dict.)
  3. Снова посмотрите на тип dict (в действительности, конечно, в нем используется сохраненный результат шага 1).Если вы найдете дескриптор, используйте его метод get ();если вы найдете что-то еще, это все;если его там нет, вызовите AttributeError.

В итоге атрибуты __dict__ и __class__ реализованы как свойства (дескрипторы данных).Чтобы поддерживать допустимое состояние, экземпляр dict не может переопределять __dict__ и __class__.Таким образом, свойства (дескрипторы данных) имеют приоритет над атрибутами экземпляра.

0 голосов
/ 18 декабря 2018

Сам Гвидо ван Россум (бывший BDFL в Python) разработал эту функцию, когда классы нового стиля были введены в Python 2.2 еще в 2001 году. Обоснование обсуждается в PEP 252 .Влияние на поиск атрибутов прямо упомянуто:

Эта схема имеет один недостаток: в том, что я считаю наиболее распространенным случаем, ссылаясь на переменную экземпляра, хранящуюся в экземпляре dict, она выполняет два поиска в словарев то время как классическая схема провела быструю проверку атрибутов, начинающихся с двух подчеркиваний и одного поиска в словаре.

И:

Эталонный тест проверяет, что на самом деле этобыстрый как классический поиск переменных экземпляра, так что я больше не беспокоюсь.

...