Класс vs экземпляр: общие изменяемые атрибуты в Python
@python_quizРазберем этот квиз
Условие (код)

Короткий ответ
- На экран будет выведено: [1]
Почему так происходит
- В строке
x = []список объявлен как атрибут класса. Атрибуты класса доступны всем экземплярам и хранятся в самом классе, а не в отдельном экземпляре. - В методе
addиспользуетсяself.x.append(v). При обращении кself.xPython сначала проверяет атрибуты объекта; если атрибут не найден, берёт атрибут класса. Поскольку экземпляры не имеют собственногоx, операция модифицирует общий список, принадлежащий классу. - В результате изменение, сделанное через
a1, видно и черезa2.
Демонстрация (выполнение)

Разбор вариантов ответа
- "[]"
- Такой вывод был бы, если бы каждый экземпляр имел свой независимый список. Здесь это не так, потому что список объявлен на уровне класса.
- "[1]"
- Соответствует действительности: общий список получил значение 1 через вызов a1.add(1).
- "[1, 1]"
- Появился бы, если бы список добавлялся дважды (например, если бы add вызывался дважды) или если бы код где-то по ошибке дважды модифицировал общий список.
- "Ошибка выполнения"
- Никакой ошибки не возникает: код корректен и выполняется.
Как избежать таких сюрпризов — правильные шаблоны
- Если нужно, чтобы каждый экземпляр имел свой список — инициализируйте его в конструкторе
__init__:

- Если хотите оставить общую структуру, но при присвоении не мутировать общий объект (то есть создать отдельный список для экземпляра при первом изменении), можно указывать присвоение нового списка:

- Если классный список должен быть общим и мутируемым — документируйте это явно и будьте осторожны:

Рекомендации
- Избегайте определения изменяемых структур (списков, словарей и т.п.) как атрибутов класса, если ожидаете независимые данные у экземпляров.
- Если вам нужен shared state — используйте явную семантику (classmethods, статические методы, переменные класса) и документируйте поведение.
- Для защиты данных можно возвращать копии:
return list(self.x)илиreturn self.x.copy().
Вывод
- В приведённом примере список
xобщий для всех экземпляров класса, поэтому изменение через один экземпляр отражается во всех остальных. Частая и типичная ловушка для начинающих — хранить изменяемые объекты на уровне класса вместо конструктора.