Так как люди в комментариях здесь и в двух других вопросах, отмеченных как дуплики, похоже, одинаково смущены этим, я думаю, что стоит добавить дополнительный ответ поверх Алекса Ковентри .
Тот факт, что Алекс присваивает значение изменяемому типу, например списку, не имеет никакого отношения к тому, являются ли объекты общими или нет. Это можно увидеть с помощью функции id
или оператора is
:
>>> class A: foo = object()
>>> a, b = A(), A()
>>> a.foo is b.foo
True
>>> class A:
... def __init__(self): self.foo = object()
>>> a, b = A(), A()
>>> a.foo is b.foo
False
(Если вам интересно, почему я использовал object()
вместо, скажем, 5
, это позволит избежать столкновения с двумя совершенно другими проблемами, которые я не хочу здесь решать; для двух разных причины, по которым полностью созданные отдельно 5
s могут оказаться тем же самым экземпляром числа 5
. Но полностью созданные по отдельности object()
s не могут.)
Итак, почему a.foo.append(5)
в примере Алекса влияет на b.foo
, а a.foo = 5
в моем примере нет? Что ж, попробуйте a.foo = 5
в примере Алекса и обратите внимание, что это не влияет на b.foo
там либо .
a.foo = 5
просто превращает a.foo
в название для 5
. Это не влияет на b.foo
или на любое другое имя для старого значения, на которое a.foo
ссылался. * Немного сложно создать атрибут экземпляра, который скрывает атрибут класса **, но как только вы получите это, ничего сложного здесь не происходит.
Надеюсь, теперь понятно, почему Алекс использовал список: тот факт, что вы можете изменять список, означает, что легче показать, что две переменные называют один и тот же список, а также означает, что в реальном коде важнее знать, есть ли у вас два списка или два имени для одного и того же списка.
* Путаница для людей, пришедших из языка, подобного C ++, заключается в том, что в Python значения не хранятся в переменных. Значения живут в value-land, сами по себе, переменные - это просто имена для значений, а присваивание просто создает новое имя для значения. Если это помогает, думайте о каждой переменной Python как shared_ptr<T>
вместо T
.
** Некоторые люди пользуются этим, используя атрибут класса в качестве «значения по умолчанию» для атрибута экземпляра, который экземпляры могут устанавливать или не устанавливать. Это может быть полезно в некоторых случаях, но также может сбивать с толку, поэтому будьте осторожны с этим.