1

有人可以解释为什么 Python 会执行以下操作吗?

>>> class Foo(object):
...   bar = []
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]
>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]
>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]

比较混乱!

4

6 回答 6

7

这是因为您编写它的方式bar是类变量而不是实例变量。

要定义实例变量,请在构造函数中绑定它:

class Foo(object):
  def __init__(self):
    self.bar = []

请注意,它现在属于Foo( self) 的单个实例而不是Foo类,您将看到分配给它时所期望的结果。

于 2010-06-15T12:52:15.917 回答
0

当您在类中声明一个元素时,该类的所有实例都共享它。要创建属于每个实例的适当类成员,请分别在 __init__ 中创建它,如下所示:

class Foo(object):
    def __init__(self):
        self.bar = []
于 2010-06-15T12:53:02.063 回答
0

一开始,bar是一个类变量,它在 and 之间共享ab两者a.bar和都b.bar引用同一个对象。

当您为 分配新值时a.bar,这不会覆盖类变量,它会向a对象添加一个新的实例变量,当您访问时隐藏类变量a.bar。如果删除a.bar(实例变量),则a.bar再次解析为类变量。

b.bar另一方面,总是指类变量,它不受对象bar上的a附加值或分配给它的任何值的影响。

要设置类变量,您可以通过类本身访问它:

Foo.bar = 1
于 2010-06-15T12:57:32.983 回答
0

正如其他人所说,编写的代码创建了一个类变量而不是实例变量。您需要分配__init__以创建实例变量。

希望这个带注释的代码副本有助于解释每个阶段发生的事情:

>>> class Foo(object):
...   bar = []          # defines a class variable on Foo (shared by all instances)
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)     # appends the value 1 to the previously empty list Foo.bar
>>> b.bar               # returns the value of the class variable Foo.bar
[1]
>>> a.bar = 1           # binds 1 to the instance variable a.bar, masking the access
>>> a.bar               # you previously had to the class variable through a.bar
1
>>> b.bar               # b doesn't have an instance variable 'bar' so this still
[1]                     # returns the class variable
>>> a.bar = []          # bind a's instance variable to to an empty list
>>> a.bar
[]
>>> b.bar               # b doesn't have an instance variable 'bar' so this still
[1]                     # returns the class variable
>>> del a.bar           # unbinds a's instance variable unmasking the class variable
>>> a.bar               # so a.bar now returns the list with 1 in it.
[1]

此外,在您的每个语句之后打印出Foo.bar(通过类而不是通过实例访问的类变量)的值可能有助于澄清发生了什么。

于 2010-06-15T13:09:12.173 回答
0
>>> class Foo(object):
...   bar = []
...

bar是共享类变量,而不是实例变量。我相信这可以解决您的大部分困惑。要使其成为实例变量,__init__请根据其他答案在类中定义它。

>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]

这就是证明。

>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]

现在您已重新定义a.bar为实例变量。这就是默认情况下在外部定义变量时发生的情况。

>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]

又是一样。b.bar仍然是共享类变量。

于 2010-06-15T13:00:00.933 回答
0

在相关的说明中,您应该意识到您可能很快就会看到的这个陷阱:

class A:
   def __init__(self, mylist = []):
      self.mylist = mylist


a = A()
a2 = A()

a.mylist.append(3)
print b.mylist #prints [3] ???

这让很多人感到困惑,并且与代码的解释方式有关。Python 实际上首先解释函数标题,因此它评估__init__(self, mylist = [])并存储对该列表的引用作为默认参数。这意味着 A 的所有实例(除非提供自己的列表)都将引用原始列表。做这种事情的正确代码是

class A:
   def __init__(self, mylist=None):
      if mylist:
         self.mylist = mylist
      else:
         self.mylist = []

或者如果你想要一个更短的表达式,你可以使用三元语法:

self.mylist = mylist if mylist else []
于 2010-06-15T13:14:25.487 回答