As all of the other other answers point out, a_list
is a class attribute, shared among all instances.
But a_number
is also a class attribute, shared among all instances. So, why is this different?
Because of this:
a.a_number = 555
That assignment creates an instance attribute a_number
in the a
instance, which hides the class attribute. If you did the same thing with the list, you'd get the same effect:
>>> b.a_list = [1,2,3]
>>> b2.a_list
[1,2]
But that's not what you do. Instead, you mutate the list in place:
b.a_list[1] = 666
That's an assignment to b.a_list[1]
, but it's not an assignment to b.a_list
. So, it doesn't create an instance attribute in the b
object.
If you could mutate a.a_number
in-place, it would also show up in a2.a_number
. Since numbers aren't mutable, there's no way to see that directly. But you can see it indirectly by comparing a.a_number is a2.a_number
or looking at their id
s—although that isn't a perfect test, because a.a_number, a2.a_number = 5, 5
, or even a.a_number, a2.a_number = 2+3, 6-1
, may still give you the same object, not because they're both still using the class attribute, but because they both now have their own instance attributes both referencing the same number 5
object.*
* The language allows the implementation to reuse the same object whenever it knows the value is immutable. In practice, the major existing implementations do this for small integers, the special singleton constants True
, False
, and None
, and maybe a few strings. With (a default-configured) CPython, 555
and 666
aren't considered small integers, but 5
is.