Appearance
Интроспекция в Python: __dict__, __dir__() и другие методы
Интроспекция позволяет программе «заглянуть внутрь» объектов и классов, узнать их атрибуты, методы и структуру без предварительного знания о них. В Python есть несколько встроенных приёмов для этого, начиная от специальных атрибутов и заканчивая модулем inspect.
Атрибут __dict__
__dict__ — это словарь, в котором хранятся все настраиваемые атрибуты экземпляра или класса (только если у класса нет __slots__).
Пример для экземпляра класса
python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("Alice", 30)
print(p.__dict__) # {'name': 'Alice', 'age': 30}Здесь p.__dict__ показывает, какие данные лежат внутри конкретного объекта.
Пример для класса
python
class Car:
wheels = 4
def __init__(self, color):
self.color = color
print(Car.__dict__['wheels']) # 4В Car.__dict__ хранится всё, что определено на уровне класса: методы, атрибуты, статичные свойства.
Метод __dir__()
__dir__() возвращает список названий атрибутов и методов объекта. По умолчанию он объединяет:
- пользовательские атрибуты в
__dict__ - методы класса и родительских классов
- встроенные «магические» методы (начинающиеся и заканчивающиеся на
__)
Пример
python
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, dx, dy):
self.x += dx; self.y += dy
pt = Point(1, 2)
print(sorted(pt.__dir__())[:10])
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', ...]Если нужно получить только пользовательские атрибуты:
python
[attr for attr in pt.__dir__() if not attr.startswith('__')]
# ['move', 'x', 'y']Другие способы инспекции классов и объектов
type(obj)
Показывает точный класс объекта.
Пример:type(123) # <class 'int'>vars(obj)
Эквивалентobj.__dict__, но работает и с модулями.
Пример:vars(pt) # {'x': 1, 'y': 2}getattr(obj, name[, default])
Достаёт значение атрибута по имени.hasattr(obj, name)
Проверяет, существует ли атрибут.Специальные атрибуты класса
Class.__bases__— кортеж базовых классовClass.__mro__— метод-разрешающий порядок при наследованииobj.__class__— класс объекта
Встроенные функции
id(obj)— уникальный идентификатор в памятиhelp(obj)— выводит документациюrepr(obj)— формальное строковое представление
Модуль inspect
Если нужно глубже копнуть, inspect даст массу полезного:
python
import inspect
# Все члены (имя, значение) объекта
inspect.getmembers(pt)
# Только функции и методы
inspect.getmembers(Point, inspect.isfunction)
# Исходный код функции или класса
print(inspect.getsource(Point))
# Сигнатура метода
print(inspect.signature(Point.move))Сравнение основных приёмов
| Приём | Что возвращает | Примечание |
|---|---|---|
obj.__dict__ | Словарь атрибутов экземпляра | Нет при __slots__ |
Class.__dict__ | Словарь атрибутов и методов класса | Включает магические методы |
obj.__dir__() | Список имён всех доступных атрибутов и методов | Включает унаследованные и __*__ |
type(obj) | Класс объекта | |
vars(obj) | Словарь атрибутов (как __dict__) | Работает для модулей |
inspect.getmembers | Список пар (имя, значение) | Фильтруется по предикату |
Что дальше?
- Изучить
__slots__и отличие от__dict__. - Погрузиться в метаклассы и хуки (
__new__,__init_subclass__). - Ознакомиться с функциями
inspect.getdoc,inspect.getmodule,inspect.isabstract. - Попробовать писать собственные декораторы для автоматического сбора метаданных.
Если хочется ещё глубже понять, как устроена интроспекция, рекомендую посмотреть исходники модуля inspect и почитать раздел об отражении в официальной документации Python.