Python类变量int vs数组

时间:2022-09-06 10:18:56

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 from Foo (because it can't find n on self)
  • 从Foo取n(因为它不能在self中找到n)
  • Creates a new value n + 1
  • 创建一个新值n + 1
  • Stores the new value in the attribute n on self
  • 在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 from Foo (because it can't find n on self)
  • 从Foo取n(因为它不能在self中找到n)
  • Creates a new value n + 1
  • 创建一个新值n + 1
  • Stores the new value in the attribute n on self
  • 在self属性n中存储新值