I was playing around with Python classes and arrived at the following example in which two variables which appear to be static class variables have different behavior when modified.
What's going on here? My first instinct is that something tricky is going on with references.
class Foo:
a = []
n = 0
def bar(self):
self.a.append('foo')
self.n += 1
x = Foo()
print x.a, x.n ([] 0)
x.bar()
print x.a, x.n (['foo', 1])
y = Foo()
print y.a, y.n (['foo', 0])
y.bar()
print y.a, y.n (['foo', 'foo'], 1)
You are correct - in the case of Foo.a
accessing self.a
actually accesses Foo.a
, which is shared between all instances of Foo
. However, when you update self.n
with +=
you actually create an instance-level variable on self
that shadows Foo.n
:
>>> import dis
>>> dis.dis(Foo.bar)
5 0 LOAD_FAST 0 (self)
3 LOAD_ATTR 0 (a)
6 LOAD_ATTR 1 (append)
9 LOAD_CONST 1 ('foo')
12 CALL_FUNCTION 1
15 POP_TOP
6 16 LOAD_FAST 0 (self)
19 DUP_TOP
20 LOAD_ATTR 2 (n)
23 LOAD_CONST 2 (1)
26 INPLACE_ADD
27 ROT_TWO
28 STORE_ATTR 2 (n)
31 LOAD_CONST 0 (None)
34 RETURN_VALUE
In other words, when you do self.a.append('some value')
the interpreter fetches a
from memory via a name on Foo
and then mutates the list that Foo.a
points to.
On the other hand, when you do self.n += 1
the interpreter:
n
from Foo
(because it can't find n
on self
)n + 1
n
on self
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With