Python 和对象/类属性 - 发生了什么?
有人可以解释为什么Python会执行以下操作吗?
>>> class Foo(object):
... bar = []
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]
>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]
>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]
真是比较混乱啊!
Can someone explain why Python does the following?
>>> class Foo(object):
... bar = []
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]
>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]
>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]
It's rather confusing!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这是因为按照您的编写方式,
bar
是一个类变量而不是实例变量。要定义实例变量,请将其绑定在构造函数中:
请注意,它现在属于
Foo
(self
) 的单个实例,而不是Foo
类,当你分配给它时,你会看到你期望的结果。This is because the way you have written it,
bar
is a class variable rather than an instance variable.To define an instance variable, bind it in the constructor:
Note that it now belongs to a single instance of
Foo
(self
) rather than theFoo
class, and you will see the results you expect when you assign to it.正如其他人所说,编写的代码创建了一个类变量而不是一个实例变量。您需要在 __init__ 中进行赋值来创建实例变量。
希望这个带注释的代码副本有助于解释每个阶段发生的情况:
此外,在之后打印出 Foo.bar 的值(通过类而不是通过实例访问的类变量)你的每一个陈述都可能有助于澄清正在发生的事情。
As others have said the code as written creates a class variable rather than an instance variable. You need to assign in
__init__
to create an instance variable.Hopefully this annotated copy of your code is helpful in explaining what's going on at each stage:
Also, printing out the value of
Foo.bar
(the class variable accessed via the class rather than via an instance) after each of your statements might help clarify what is going on.当您在类中声明一个元素时,该元素将被该类的所有实例共享。要分别创建属于每个实例的正确类成员,请在 __init__ 中创建它,如下所示:
When you declare an element in the class like that it is shared by all instances of the class. To make a proper class member that belongs to each instance, separately, create it in __init__ like the following:
一开始,
bar
是一个类变量,它在a
和b
之间共享,两者都是a.bar
和 b.bar 引用同一个对象。当您向
a.bar
分配新值时,这不会覆盖类变量,而是向a
对象添加一个新的实例变量,从而在您指定时隐藏该类变量。访问a.bar
。如果删除a.bar
(实例变量),则a.bar
再次解析为类变量。另一方面,b.bar 始终引用类变量,它不受
a
对象上附加的bar
或分配的任何值的影响对此。要设置类变量,您可以通过类本身访问它:
In the beginning,
bar
is a class variable and it is shared betweena
andb
, botha.bar
andb.bar
refer to the same object.When you assign a new value to
a.bar
, this does not overwrite the class variable, it adds a new instance variable to thea
object, hiding the class variable when you accessa.bar
. If you deletea.bar
(the instance variable), thena.bar
resolves again to the class variable.b.bar
on the other hand always refers to the class variable, it's not influenced by the additionalbar
on thea
object or any values assigned to that.To set the class variable you can access it through the class itself:
bar
是一个共享类变量,而不是实例变量。我相信这可以解决您的大部分困惑。要使其成为实例变量,请根据其他答案在类的 __init__ 中定义它。这就是证明。
现在您已将
a.bar
重新定义为实例变量。这就是默认情况下在外部定义变量时发生的情况。又一样。
b.bar
仍然是共享类变量。bar
is a shared class variable, not an instance variable. I believe that deals with most of your confusion. To make it a instance var, define it in class's__init__
per the other answers.This is the proof of that.
Now you've redefined
a.bar
as a instance variable. That's what happens when you define variables externally by default.Same again.
b.bar
is still the shared class variable.与此相关的是,您应该意识到您可能很快就会看到的这个陷阱:
这让很多人感到困惑,并且与代码的解释方式有关。 Python 实际上首先解释函数标题,因此它会计算 __init__(self, mylist = []) 并将对该列表的引用存储为默认参数。这意味着 A 的所有实例(除非提供它们自己的列表)都将引用原始列表。执行此类操作的正确代码是,
或者如果您想要更短的表达式,您可以使用三元语法:
On a related note, you should be aware of this pitfall that you might see sometime soon:
This confuses a lot of folks and has to do with how the code is interpreted. Python actually interprets the function headings first, so it evaluates
__init__(self, mylist = [])
and stores a reference to that list as the default parameter. That means that all instances of A will (unless provided their own list) reference the original list. The correct code for doing such a thing would beor if you want a shorter expression you can use the ternary syntax: