我一直在努力理解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 ++,所以通过类比解释(或指出它崩溃的地方)可能是有用的。
答案 0 :(得分:5)
就我个人而言,我发现Shalabh Chaturvedi these documents对这个主题非常有用且内容丰富。
bar.num += 1
是bar.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
是一个实例成员(self
是Foo
的一个实例。)
在C ++中,它会像
struct Foo {
int num;
};
我相信Python允许你有一个类成员和一个实例成员共享相同的名称(C ++没有)。因此,当您执行bar = Foo()
时,bar
是Foo
的实例,因此使用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(1,2)的两张(相当陈旧但有效)幻灯片都出现了问题。 Guido的幻灯片说明这种行为与Python的访问属性的搜索顺序有关(在上面的例子num
的情况下)。认为将两者放在一起很好:)
答案 4 :(得分:-3)
我认为你刚刚在Python中发现了一个bug。 bar.num + = 1应该是一个错误,而是在对象栏中创建一个属性num,与Foo.num不同。
这是一种非常奇怪的行为。