Compound assignment to Python class and instance variables
我一直试图理解Python对类和实例变量的处理。特别是,我发现这个答案非常有用。基本上说,如果您声明一个类变量,然后对
所以我考虑——如果我希望类的每个实例都有一个具有一些默认值(比如零)的成员,我应该这样做吗:
1 2 | class Foo: num = 0 |
或者像这样?
1 2 3 | class Foo: def __init__(self): self.num = 0 |
根据我之前读到的内容,我认为第二个示例将初始化"right"变量(实例而不是类变量)。但是,我发现第一种方法也非常有效:
1 2 3 4 5 6 7 8 9 | 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? |
所以…为什么会这样?我没有得到什么?FWW,我以前对OOP的理解来自C++,所以类比的解释(或者指向它的崩溃)可能是有用的。
就我个人而言,我发现沙拉布·查图维迪的这些文件对于这一主题非常有用和有用。
在下面的代码中,
1 2 | class Foo: num = 0 |
一个C++等价物会是一个类似的东西。
1 2 3 4 5 | struct Foo { static int num; }; int Foo::num = 1; |
1 2 3 | class Foo: def __init__(self): self.num = 0 |
在C++中,它会有点像
1 2 3 | struct Foo { int num; }; |
我相信Python允许你有一个类成员和一个实例成员共享同一个名字(C++没有)。所以当你做
为了寻找这个问题,这个stackoverflow问题和guido van rossum(1,2)的两张(相当旧,但有效)幻灯片都出现在了较高的位置。guido的幻灯片中指出,这种行为与python访问属性的搜索顺序有关(在上面的示例中为
1 | bar.num += 1 |
在"bar"实例上创建一个新的实例变量"num",因为它尚不存在(然后向该值添加1)
一个例子:
1 2 3 4 5 6 | class Foo: def __init__(self): self.num= 1 bar = Foo() print bar.num |
这张照片1张
1 | print bar.foo |
这将按预期给出错误:回溯(最近调用的最后一次):文件",第1行,inattributeError:foo实例没有属性"foo"
1 2 | bar.foo = 5 print bar.foo |
现在这张照片5
所以在您的示例中会发生什么:bar.num被解析为foo.num,因为只有一个class属性。然后会实际创建foo.num,因为您为其指定了一个值。
我想你刚刚在那里发现了一个Python的虫子。bar.num+=1应该是一个错误,相反,它正在对象栏中创建一个与foo.num不同的属性num。
这真是一种奇怪的行为。