Приписывайте свой успех Python
Головоломка Python
Как вы думаете, что напечатает следующая программа?
Эта программа завершится ошибкой: RecursionError: maximum recursion depth exceeded
.
Поиск атрибутов Python, который происходит каждый раз, когда вы, например, пишете now.year
, довольно сложен. У вас как у разработчика есть множество возможностей изменить способ поиска атрибутов в ваших классах: свойства, искаженные имена (например, __name
), staticmethod
, classmethod
, __slots__
, дескрипторы и многое другое.
Вы также можете реализовать два специальных метода для динамического вычисления атрибутов, это __getattribute__
и __getattr__
. Вы захотите использовать __getattr__
:)
Смотрим документацию:
__getattr__
: вызывается при сбое доступа к атрибуту по умолчанию с ошибкой AttributeError…__getattribute__
: вызывается безоговорочно для реализации доступа к атрибутам для экземпляров класса. Если класс также определяет__getattr__
, то последний вызываться не будет...
Таким образом, согласно документации, __getattr__
вызывается только тогда, когда обычный поиск атрибутов терпит неудачу. В нашем случае запись new._obj
ничего не напечатает, но запись now.year
запустит наш метод __getattr__
(поскольку now
не имеет атрибута year
) и напечатает.
С другой стороны, __getattribute__
полностью обходит обычный поиск атрибутов. Строка val = getattr(self._obj, attr, None)
будет вызывать нашу __getattribute__
снова и снова, пока мы не достигнем встроенного предела рекурсии Python.
Исправить легко — переключитесь на __getattr__
:
Который будет печатать:
[DEBUG] year -> 2022 2022
Я не могу вспомнить ни одного раза за двадцать пять лет написания кода на Python, чтобы я использовал __getattribute__
. Я использовал __getattr__
несколько раз, например, при написании прокси.)
🎓 Дальнейшее изучение. Я рекомендую посмотреть видео Рэймонда Хеттингера Инструменты для разработки классов. Это даст вам хорошее представление о том, когда использовать некоторые из упомянутых инструментов. Или, если вы хотите спуститься в кроличью нору кода C, начните с PyObject_GetAttr
в object.c и следуйте коду.
Если вам нравится решать задачи по программированию, ознакомьтесь с книгами Мики Тебека «Дразнилки для ума» на The Pragmatic Bookshelf. Вы можете сэкономить 35% на электронных версиях книг с промокодом brain_teasers_35 до 15 сентября 2022 года: