为什么类的新实例与其他实例共享成员?

时间:2008-11-21 03:22:54

标签: python scope mutable

class Ball:
  a = []
  def __init__(self):
    pass

  def add(self,thing):
    self.a.append(thing)

  def size(self):
    print len(self.a)

for i in range(3):
  foo = Ball()
  foo.add(1)
  foo.add(2)
  foo.size()

我希望回归:

2
2
2

但我明白了:

2
4
6

这是为什么?我发现通过在 init 中执行= [],我可以绕过这种行为,但我不清楚为什么。

3 个答案:

答案 0 :(得分:4)

DOH

我只知道原因。

在上面的例子中,a是类属性,而不是数据属性 - 所有Balls()都共享它们。注释掉a = []并将其放入 init 块意味着它是一个数据属性。 (并且,我无法使用foo.a访问它,我不应该这样做。)看起来类属性就像类的静态属性一样,它们由所有实例共享。

哇。

但有一个问题:CodeCompletion很糟糕。在foo类中,我不能自我。(变量),因为它不是自动定义的 - 它是由函数定义的。我可以定义一个类变量并将其替换为数据变量吗?

答案 1 :(得分:2)

您可能想要做的是:

class Ball:
  def __init__(self):
    self.a = []

如果仅使用a = [],它会在__init__函数中创建一个局部变量,该函数在函数返回时消失。分配给self.a会使它成为您所追求的实例变量。

对于半相关问题,请参阅change the value of default parameters for future callers

答案 2 :(得分:1)

“我可以定义一个类变量并用数据变量替换它吗?”

没有。它们是分开的东西。类变量只存在一次 - 在类中。

你可以 - 精确代码完成 - 从一些类变量开始,然后在编写完类后删除这些代码行。但每当你忘记这样做,就不会发生任何好事。

更好的是尝试不同的IDE。 Komodo Edit的代码完成似乎是明智的。

如果你有这么多长名称的变量,代码完成实际上是有用的,也许你应该让你的类更小或使用更短的名称。认真。

我发现当你到达一个代码完成比烦人更有帮助的地方时,你已经超出了“保持一切在我脑中”的复杂性阈值。如果班级不适合我的大脑,那就太复杂了。