Ответ
В Python атрибуты класса хранятся в специальном словаре __dict__, который принадлежит самому объекту класса. Этот словарь сопоставляет имена атрибутов с их значениями.
Ключевые моменты:
- Хранение: Атрибуты, определенные непосредственно в теле класса, попадают в
__dict__этого класса. - Доступ: К ним можно получить доступ как через класс (
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 выполняет поиск в следующем порядке:
- Сначала в словаре
__dict__самого экземпляра (d1). - Если атрибут не найден, поиск продолжается в
__dict__его класса (Dog). - Если и там его нет, поиск идет по иерархии родительских классов в соответствии с MRO (Method Resolution Order).
Это объясняет, почему все экземпляры имеют доступ к атрибутам класса, но у каждого из них есть свой собственный набор атрибутов экземпляра.
Ответ 18+ 🔞
Смотри, объясняю про эти ваши питоновские атрибуты, как устроено, блядь. Всё просто, как три копейки, ёпта.
Вот есть у тебя класс, да? У него есть своя внутренняя шкатулка, называется __dict__. Это типа такой словарик, куда он все свои штуки складывает — те, что прямо в теле класса объявил.
Суть, на которую можно наступить:
- Где лежит: Всё, что ты накатал прямо под
class Dog:, летит прямиком в__dict__этого самого класса. Как в общий холодильник на работе. - Кому доступно: До этой общей тумбочки могут дотянуться и сам класс (
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, Питон не тупит, а делает так:
- Первым делом лезет в личный ящик экземпляра (
d1.__dict__). "Ну чё, имя есть, а species-то где?" - Не нашёл? Идёт шарить в общую тумбочку класса (
Dog.__dict__). "Ага, вот же, species, на всех хватит!" - И там нет? Тогда начинает обламывать родителей, лезет по цепочке наследования, смотрит в их тумбочки. По этому самому MRO (Method Resolution Order), который тоже, блядь, придумали не просто так.
Вот поэтому все экземпляры видят атрибуты класса, но при этом у каждого своя личная жизнь в виде атрибутов экземпляра. Всё гениальное — просто, как палка о двух концах.