复合赋值给Python类和实例变量

时间:2010-03-11 11:21:52

标签: python class

我一直在努力理解Python对类和实例变量的处理。特别是,我发现this answer非常有帮助。基本上它说如果你声明一个类变量,然后你对[instance].property做一个赋值,你将完全分配一个不同的变量 - 一个在与类变量不同的命名空间中。

所以我考虑过 - 如果我希望我的类的每个实例都有一个默认值(比如零)的成员,我应该这样做:

class Foo:
    num = 0

还是喜欢这个?

class Foo:
    def __init__(self):
        self.num = 0

根据我之前读过的内容,我认为第二个例子是初始化'right'变量(实例而不是类变量)。但是,我发现第一种方法也非常有效:

class Foo:
    num = 0

bar = Foo()
bar.num += 1 # good, no error here, meaning that bar has an attribute 'num'
bar.num
>>> 1
Foo.num
>>> 0 # yet the class variable is not modified! so what 'num' did I add to just now?

那么......为什么会这样?我得不到什么? FWIW,我之前对OOP的理解来自C ++,所以通过类比解释(或指出它崩溃的地方)可能是有用的。

5 个答案:

答案 0 :(得分:5)

就我个人而言,我发现Shalabh Chaturvedi these documents对这个主题非常有用且内容丰富。

bar.num += 1bar.num = bar.num + 1的简写。这是在右侧拾取类变量Foo.num并将其分配给实例变量bar.num

答案 1 :(得分:2)

在以下代码中,num是类成员。

class Foo:
    num = 0

C ++等价物就像

struct Foo {
  static int num;
};

int Foo::num = 1;

class Foo:
    def __init__(self):
        self.num = 0

self.num是一个实例成员(selfFoo的一个实例。)

在C ++中,它会像

struct Foo {
  int num;
};

我相信Python允许你有一个类成员和一个实例成员共享相同的名称(C ++没有)。因此,当您执行bar = Foo()时,barFoo的实例,因此使用bar.num += 1,您可以增加实例成员。

答案 2 :(得分:0)

bar.num += 1

在'bar'实例上创建一个新的实例变量'num',因为它尚不存在(然后将此值加1)

一个例子:

class Foo:
  def __init__(self):
    self.num= 1

bar = Foo()
print bar.num

这打印1

print bar.foo

这会出现预期的错误:Traceback(最近一次调用最后一次):   文件“”,第1行,in AttributeError:Foo实例没有属性'foo'

bar.foo = 5
print bar.foo

现在打印5

所以在你的例子中会发生什么:bar.num被解析为Foo.num因为只有一个class属性。然后实际创建了foo.num,因为你为它赋值。

答案 3 :(得分:0)

在搜索这个问题时,这个StackOverflow问题和Guido van Rossum(12)的两张(相当陈旧但有效)幻灯片都出现了问题。 Guido的幻灯片说明这种行为与Python的访问属性的搜索顺序有关(在上面的例子num的情况下)。认为将两者放在一起很好:)

答案 4 :(得分:-3)

我认为你刚刚在Python中发现了一个bug。 bar.num + = 1应该是一个错误,而是在对象栏中创建一个属性num,与Foo.num不同。

这是一种非常奇怪的行为。