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.
我正在摆弄Python类,并得到了下面的示例,其中两个看起来是静态类变量的变量在修改时具有不同的行为。
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)
1 个解决方案
#1
5
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
:
你是对的-对于Foo。一个访问的自我。实际*问Foo。a,在Foo的所有实例之间共享。然而,当你更新自我。n with +=你实际上在self上创建了一个实例级变量,阴影在后面。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.
换句话说,当你做自我的时候。追加('some value')解释器通过Foo上的一个名称从内存中获取一个,然后修改Foo的列表。一个指向。
On the other hand, when you do self.n += 1
the interpreter:
另一方面,当你做自我的时候。n += 1译员:
- Fetches
n
fromFoo
(because it can't findn
onself
) - 从Foo取n(因为它不能在self中找到n)
- Creates a new value
n + 1
- 创建一个新值n + 1
- Stores the new value in the attribute
n
onself
- 在self属性n中存储新值
#1
5
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
:
你是对的-对于Foo。一个访问的自我。实际*问Foo。a,在Foo的所有实例之间共享。然而,当你更新自我。n with +=你实际上在self上创建了一个实例级变量,阴影在后面。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.
换句话说,当你做自我的时候。追加('some value')解释器通过Foo上的一个名称从内存中获取一个,然后修改Foo的列表。一个指向。
On the other hand, when you do self.n += 1
the interpreter:
另一方面,当你做自我的时候。n += 1译员:
- Fetches
n
fromFoo
(because it can't findn
onself
) - 从Foo取n(因为它不能在self中找到n)
- Creates a new value
n + 1
- 创建一个新值n + 1
- Stores the new value in the attribute
n
onself
- 在self属性n中存储新值