对Python类和实例变量的复合赋值
我一直在尝试理解Python是如何处理类变量和实例变量的。特别是,我发现这个回答非常有帮助。简单来说,它说如果你声明了一个类变量,然后给[instance].property
赋值,你实际上是在给一个完全不同的变量赋值——这个变量在一个和类变量不同的命名空间里。
所以我考虑了,如果我想让我的类的每个实例都有一个默认值的成员(比如说零),我应该这样做:
class Foo:
num = 0
还是这样做呢?
class Foo:
def __init__(self):
self.num = 0
根据我之前读到的内容,我觉得第二个例子是在初始化“正确”的变量(也就是实例变量,而不是类变量)。然而,我发现第一种方法也能很好地工作:
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?
那么……为什么这样也能工作呢?我到底没理解什么?顺便说一下,我之前对面向对象编程的理解主要来自C++,所以通过类比来解释(或者指出哪里出错)可能会很有帮助。
5 个回答
bar.num += 1
在这个例子中,'bar'这个实例上创建了一个新的变量'num',因为之前并不存在这个变量(然后这个变量的值加1)。
举个例子:
class Foo:
def __init__(self):
self.num= 1
bar = Foo()
print bar.num
这会打印出1
print bar.foo
这会出现一个错误,正如预期的那样:追踪(最近的调用最后): 文件 "", 第1行,在 属性错误:Foo实例没有属性'foo'
bar.foo = 5
print bar.foo
现在这会打印出5
那么在你的例子中发生了什么呢:bar.num被解析为Foo.num,因为只有一个类属性。然后foo.num实际上是被创建了,因为你给它赋了一个值。
在下面的代码中,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
这行代码,你是在增加这个实例成员的值。
我个人觉得,Shalabh Chaturvedi写的这些文档在这个话题上非常有用,也很有信息量。
bar.num += 1
其实是bar.num = bar.num + 1
的简写。这段代码的意思是,它在右边取出类变量Foo.num
的值,然后把这个值加1后再赋值给实例变量bar.num
。