Где в Python хранятся атрибуты класса и как устроен доступ к ним?

Ответ

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

Ключевые моменты:

  1. Хранение: Атрибуты, определенные непосредственно в теле класса, попадают в __dict__ этого класса.
  2. Доступ: К ним можно получить доступ как через класс (MyClass.attr), так и через его экземпляры (my_instance.attr).

Пример:

class Dog:
    # Атрибут класса, общий для всех экземпляров
    species = "Canis familiaris"

    def __init__(self, name):
        # Атрибут экземпляра, уникальный для каждого объекта
        self.name = name

# Доступ к __dict__ класса
# print(Dog.__dict__)
# Вывод будет содержать 'species': 'Canis familiaris', __init__, и др.

# Создание экземпляров
d1 = Dog("Rex")
d2 = Dog("Buddy")

# Атрибут 'species' берется из __dict__ класса Dog
print(d1.species)  # -> Canis familiaris
print(d2.species)  # -> Canis familiaris

# Атрибут 'name' находится в __dict__ конкретного экземпляра
print(d1.__dict__) # -> {'name': 'Rex'}
print(d2.__dict__) # -> {'name': 'Buddy'}

Механизм поиска атрибутов:

Когда вы обращаетесь к атрибуту через экземпляр (например, d1.species), Python выполняет поиск в следующем порядке:

  1. Сначала в словаре __dict__ самого экземпляра (d1).
  2. Если атрибут не найден, поиск продолжается в __dict__ его класса (Dog).
  3. Если и там его нет, поиск идет по иерархии родительских классов в соответствии с MRO (Method Resolution Order).

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

Ответ 18+ 🔞

Смотри, объясняю про эти ваши питоновские атрибуты, как устроено, блядь. Всё просто, как три копейки, ёпта.

Вот есть у тебя класс, да? У него есть своя внутренняя шкатулка, называется __dict__. Это типа такой словарик, куда он все свои штуки складывает — те, что прямо в теле класса объявил.

Суть, на которую можно наступить:

  1. Где лежит: Всё, что ты накатал прямо под class Dog:, летит прямиком в __dict__ этого самого класса. Как в общий холодильник на работе.
  2. Кому доступно: До этой общей тумбочки могут дотянуться и сам класс (Dog.attr), и любой его экземпляр (my_dog.attr). Все сосут из одной миски, пока свою не нальют.

Смотри пример, чтобы не ебать мозг:

class Dog:
    # Это атрибут класса — общий для всех псов, как порода
    species = "Canis familiaris"

    def __init__(self, name):
        # А это атрибут экземпляра — у каждого своя кличка, своя жопа
        self.name = name

# Заглянем в общую тумбочку класса
# print(Dog.__dict__)
# Увидишь там 'species': 'Canis familiaris', этот самый __init__, и прочую хуйню.

# Рожаем собакенов
d1 = Dog("Rex")
d2 = Dog("Buddy")

# Атрибут 'species' тянется из общей тумбочки класса Dog
print(d1.species)  # -> Canis familiaris
print(d2.species)  # -> Canис familiaris (ой, бля, опечатка, но суть та же)

# А вот 'name' — это уже личная собственность каждого экземпляра, в его личном ящике
print(d1.__dict__) # -> {'name': 'Rex'}
print(d2.__dict__) # -> {'name': 'Buddy'}

Как Python ищет атрибуты, или алгоритм "Где я это оставил, блядь?":

Когда ты пишешь d1.species, Питон не тупит, а делает так:

  1. Первым делом лезет в личный ящик экземпляра (d1.__dict__). "Ну чё, имя есть, а species-то где?"
  2. Не нашёл? Идёт шарить в общую тумбочку класса (Dog.__dict__). "Ага, вот же, species, на всех хватит!"
  3. И там нет? Тогда начинает обламывать родителей, лезет по цепочке наследования, смотрит в их тумбочки. По этому самому MRO (Method Resolution Order), который тоже, блядь, придумали не просто так.

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