Since people in the comments here and in two other questions marked as dups all appear to be confused about this in the same way, I think it's worth adding an additional answer on top of Alex Coventry's.
The fact that Alex is assigning a value of a mutable type, like a list, has nothing to do with whether things are shared or not. We can see this with the id
function or the is
operator:
>>> 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
(If you're wondering why I used object()
instead of, say, 5
, that's to avoid running into two whole other issues which I don't want to get into here; for two different reasons, entirely separately-created 5
s can end up being the same instance of the number 5
. But entirely separately-created object()
s cannot.)
So, why is it that a.foo.append(5)
in Alex's example affects b.foo
, but a.foo = 5
in my example doesn't? Well, try a.foo = 5
in Alex's example, and notice that it doesn't affect b.foo
there either.
a.foo = 5
is just making a.foo
into a name for 5
. That doesn't affect b.foo
, or any other name for the old value that a.foo
used to refer to.* It's a little tricky that we're creating an instance attribute that hides a class attribute,** but once you get that, nothing complicated is happening here.
Hopefully it's now obvious why Alex used a list: the fact that you can mutate a list means it's easier to show that two variables name the same list, and also means it's more important in real-life code to know whether you have two lists or two names for the same list.
* The confusion for people coming from a language like C++ is that in Python, values aren't stored in variables. Values live off in value-land, on their own, variables are just names for values, and assignment just creates a new name for a value. If it helps, think of each Python variable as a shared_ptr<T>
instead of a T
.
** Some people take advantage of this by using a class attribute as a "default value" for an instance attribute that instances may or may not set. This can be useful in some cases, but it can also be confusing, so be careful with it.