← Все вопросы

Почему список как атрибут класса оказался общим для всех экземпляров?

Задан 10 месяцев назад588 просмотров3 ответа
20

Сделал так:

class Basket:
    items = []
    def add(self, x):
        self.items.append(x)

a = Basket()
b = Basket()
a.add('яблоко')
print(b.items)  # ['яблоко'] — почему?!

Добавляю в a, а оно появляется и в b. Я же создал два разных объекта. В чём подвох?

3 ответа

28
✓ Принятый ответ — помог автору

items = [] объявлен на уровне класса, а не в __init__, поэтому это один общий список, разделяемый всеми экземплярами. self.items.append(...) не создаёт новый список — он находит общий через класс и мутирует его, поэтому изменение видно у всех.

Правильно — заводить изменяемые атрибуты в __init__, тогда у каждого объекта свой список:

class Basket:
    def __init__(self):
        self.items = []   # свой список на каждый экземпляр
    def add(self, x):
        self.items.append(x)

Это классическая грабля. Атрибуты класса хороши для констант/неизменяемых значений (которые общие осознанно), а всё изменяемое (списки, словари) держи в __init__.

Григорий Антонов Правило: mutable → в __init__, всегда · 10 месяцев назад
Кирилл Андервуд Та же причина, что и mutable default argument — общий объект, который мутируют · 10 месяцев назад
10

Потому что items — атрибут класса, он один на всех. Перенеси self.items = [] в __init__.

-5

Список создаётся заново при каждом создании объекта, у тебя где-то другая ошибка.

Evgeniy Arapov Нет, это и есть суть проблемы: атрибут класса общий. В __init__ он бы создавался заново, а на уровне класса — нет · 10 месяцев назад

Ваш ответ

Войдите, чтобы ответить на вопрос.
Поддержать проект