Skip to content

Интроспекция в 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.

Упражнения