Если вы когда-либо работали с Python internals, создавали собственные классы, ORM, прокси-объекты, lazy loading или просто пытались понять, как работает доступ к атрибутам — этот разбор обязателен к прочтению.
На первый взгляд все эти dunder-методы выглядят одинаково: они что-то «получают» (`get`). Но в действительности каждый отвечает за отдельный механизм Python.
1️⃣
.__getitem__()Этот метод вызывается, когда вы используете квадратные скобки:
obj[key]
Python автоматически превращает это в:
obj.__getitem__(key)
Именно поэтому списки, словари, строки и кастомные контейнеры умеют работать через индекс или ключ.
Например, можно создать класс, который:
• принимает несколько ключей сразу
• ограничивает доступ к данным
• меняет поведение индексации
• реализует собственную логику выборки
2️⃣
.__getattribute__()Каждый раз, когда вы пишете:
obj.attribute
Python ВСЕГДА сначала вызывает:
obj.__getattribute__("attribute")
Именно этот метод решает:
— является ли объект data descriptor
— есть ли attribute у экземпляра (`instance.__dict__`)
— существует ли non-data descriptor
— есть ли атрибут у класса
— нужно ли запускать fallback-механизм
⚠️ Переопределять
.__getattribute__() нужно крайне осторожно — легко сломать доступ ко всем атрибутам объекта.3️⃣
.__getattr__()Этот метод вызывается только если Python не нашёл атрибут обычным способом.
Например:
obj.username
Если
username не существует, Python попробует:
obj.__getattr__("username")
Это полезно для:
• lazy loading
• динамических атрибутов
• delegation/proxy objects
• ORM-моделей
• API wrappers
Например, можно автоматически брать значения из словаря:
obj.name
вместо:
obj["name"]
4️⃣
.__get__()Самый недооценённый механизм Python.
Если класс реализует:
__get__()
то он становится descriptor.
Descriptors лежат в основе:
•
@property• bound methods
•
classmethod•
staticmethod• ORM field systems (Django, SQLAlchemy)
• validation frameworks
Python использует descriptors буквально повсюду.
🔥 Порядок поиска атрибута в Python
Когда вызывается:
obj.attribute
Python проверяет:
1. Data descriptor (`__get__ + __set__`)
2. Instance attribute (`obj.__dict__`)
3. Non-data descriptor (`__get__`)
4. Class attribute
5.
.__getattr__() как fallback📍 Навигация: Вакансии • Задачи • Собесы
Библиотека питониста
#буст
