Что такое служебный атрибут __dict__ в Python?

Ответ

__dict__ — это специальный атрибут, который хранит изменяемое пространство имен объекта в виде словаря. В нем содержатся атрибуты экземпляра класса.

Пример использования:

class Project:
    def __init__(self, name, priority):
        self.name = name
        self.priority = priority
        self.status = 'active'

project = Project('API Migration', 'high')

# __dict__ содержит атрибуты экземпляра
print(project.__dict__)
# Вывод: {'name': 'API Migration', 'priority': 'high', 'status': 'active'}

# Динамическое изменение атрибутов через __dict__
project.__dict__['deadline'] = '2024-12-01'
print(project.deadline)  # 2024-12-01

# Удаление атрибута
del project.__dict__['status']

Важные детали:

  • Для экземпляров: obj.__dict__ хранит атрибуты, назначенные через self.attr или динамически.
  • Для классов: ClassName.__dict__ хранит атрибуты класса, включая методы (он является более сложным объектом mappingproxy).
  • Ограничения: Объекты, классы которых определяют __slots__, не имеют атрибута __dict__ для экономии памяти. Также его нет у многих встроенных типов (например, list, int).
  • Применение: Часто используется для сериализации, интроспекции (например, в ORM) или динамического управления атрибутами.

Ответ 18+ 🔞

Эй, слушай, а вот этот __dict__ — это же просто пиздец какой удобный штука, я тебе скажу. Представь, что у тебя есть объект, и ты хочешь знать, что у него внутри, как в карманах у бомжа после хорошей помойки. Так вот, __dict__ — это и есть эти карманы, только в виде словаря Python.

Смотри, как это просто работает, ёпта:

class Project:
    def __init__(self, name, priority):
        self.name = name
        self.priority = priority
        self.status = 'active'

project = Project('API Migration', 'high')

# Заглядываем в его внутренности через __dict__
print(project.__dict__)
# Вывод: {'name': 'API Migration', 'priority': 'high', 'status': 'active'}

Видишь? Всё как на ладони. И самое охуенное — ты можешь туда лезть и всё менять на лету, прямо как в бардачке у таксиста.

# Хуяк — и новый атрибут из воздуха
project.__dict__['deadline'] = '2024-12-01'
print(project.deadline)  # 2024-12-01

# А можно и нахуй что-то выкинуть
del project.__dict__['status']

Но, чувак, тут не всё так просто, как кажется. Есть нюансы, про которые надо помнить, а то доверия ебать ноль к этой магии.

  • Для объектов (экземпляров): obj.__dict__ показывает всё, что ты туда напихал через self.что-то или динамически. Это его личные шмотки.
  • Для самих классов: ClassName.__dict__ — это уже другая история. Там лежат атрибуты всего класса, включая методы. Это как общий семейный сейф, только доступ к нему через mappingproxy — такая защитная прослойка, чтобы ты не накосячил.
  • Подводные камни: А вот тут внимание. Если класс использует __slots__ для экономии памяти (чтобы не таскать за собой этот словарь), то у его объектов __dict__ просто не будет. Вообще. Попробуешь обратиться — получишь AttributeError и полное удивление пиздец. То же самое и со встроенными типами вроде списков или чисел — у них его нет.
  • Где применить: А применяется это дело, бля, везде. Нужно объект в JSON превратить? Загляни в __dict__. Пишешь свою ORM или фреймворк, чтобы понять, какие поля у модели? __dict__ в помощь. Динамически атрибуты навешиваешь? Да без него никуда.

Короче, инструмент мощный, но, как и любой острый инструмент, требует аккуратности. Не лезь туда бездумно, а то можно такого наворотить, что потом сам от себя охуеешь.