具有非 None 类属性的类的新实例?
我有一个 Python 类,其类属性设置为 None
以外的值。创建新实例时,对该属性所做的更改将在所有实例中永久存在。
下面是一些代码来解释这一点:
class Foo(object):
a = []
b = 2
foo = Foo()
foo.a.append('item')
foo.b = 5
使用 foo.a
返回 ['item']
和 foo.b
返回 5< /code>,正如人们所期望的那样。
当我创建一个新实例(我们将其称为 bar
)时,使用 bar.a
返回 ['item']
和 bar.b
也返回 5
!但是,当我最初将所有类属性设置为 None
时,然后将它们设置为 __init__
中的任何内容,如下所示:
class Foo(object):
a = None
b = None
def __init__(self):
self.a = []
self.b = 2
使用 bar.a
返回 < code>[] 和 bar.b
返回 2
,而 foo.a
返回 ['item'] 和 foo.b 返回
5
。
这就是它的工作原理吗?显然,在我编写 Python 的 3 年里,我从未遇到过这个问题,并且希望得到一些澄清。我在文档中也找不到它,所以如果可能的话给我一个参考就太好了。 :)
I have a Python class that has a class attribute set to something other than None
. When creating a new instance, the changes made to that attribute perpetuates through all instances.
Here's some code to make sense of this:
class Foo(object):
a = []
b = 2
foo = Foo()
foo.a.append('item')
foo.b = 5
Using foo.a
returns ['item']
and foo.b
returns 5
, as one would expect.
When I create a new instance (we'll call it bar
), using bar.a
returns ['item']
and bar.b
return 5
, too! However, when I initially set all the class attributes to None
then set them to whatever in __init__
, like so:
class Foo(object):
a = None
b = None
def __init__(self):
self.a = []
self.b = 2
Using bar.a
returns []
and bar.b
returns 2
while foo.a
returns ['item']
and foo.b
returns 5
.
Is this how it's suppose to work? I've apparently never ran into this issue in the 3 years I've programmed Python and would like some clarification. I also can't find it anywhere in the documentation, so giving me a reference would be wonderful if possible. :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
是的,这就是它应该如何工作的。
如果
a
和b
属于Foo
的实例,那么正确的做法是:使
a
和b
属于类本身,因此所有实例共享相同的变量:当您混合使用这两种方法时 - 正如您所做的那样在你的第二个例子中——这不会添加任何有用的东西,只会引起混乱。
值得一提的一个警告是,当您在第一个示例中执行以下操作时:
您没有更改
Foo.b
,而是向foo
添加了一个全新的属性,该属性“遮蔽“Foo.b
.当您执行此操作时,bar.b
和Foo.b
都不会改变。如果您随后执行del foo.b
,则会删除该属性,并且foo.b
将再次引用Foo.b
。Yes, this is how it is supposed to work.
If
a
andb
belong to the instance ofFoo
, then the correct way to do this is:The following makes
a
andb
belong to the class itself, so all instances share the same variables:When you mix the two methods -- as you did in your second example -- this doesn't add anything useful, and just causes confusion.
One caveat worth mentioning is that when you do the following in your first example:
you are not changing
Foo.b
, you are adding a brand new attribute tofoo
that "shadows"Foo.b
. When you do this, neitherbar.b
norFoo.b
change. If you subsequently dodel foo.b
, that'll delete that attribute andfoo.b
will once again refer toFoo.b
.是的,这正是您所期望的。当您在类上定义变量时,这些属性将附加到类,而不是实例。您可能并不总是注意到,当您分配给实例上的属性时,实例会获取新值,从而屏蔽类属性。 就地修改的方法(例如
list.append
)不会为实例提供新属性,因为它们只是修改现有对象,而该对象恰好是该类的属性。任何时候,类的每个实例都应该有自己唯一的属性值,通常应该在 __init__ 方法中设置该值,以确保每个实例的值都不同。
仅当类具有具有合理默认值的属性,并且该值属于不可变类型(无法就地修改)时,例如
int
或str
,您是否应该在类上设置属性。Yes, that's exactly what you should expect. When you define a variable on the class, then those attributes are attached to the class, not the instance. You might not always notice that when you assign to an attribute on an instance, the instance picks up the new value, masking the class attribute. Methods that modify in place, like
list.append
won't give the instance a new attribute, since they just modify existing object, which happens to be an attribute of the class.Any time every instance of a class should have its own, unique value for an attribute, you should usually set that in the
__init__
method, to be sure that it's different for every instance.only when a class has an attribute that has a sensible default value, and that value is of an immutable type (that cannot be modified in place), such as
int
orstr
, should you set attributes on the class.是的,一开始似乎令人惊讶,但正如其他答案中所述,这就是 python 的工作方式。三年巨蟒没有被这个砍掉?你很幸运,非常幸运。如果我是你,我会检查小动物的敏感过去代码...
也要小心函数调用:
def func(list=[])
有类似的行为,这可能会令人惊讶。并且,如果可能的话,在提交挂钩中插入 pylint 解析。或者至少在你的代码上运行 pylint ,它非常有启发性,并且可能会告诉你这个技巧(这不是一个技巧,事实上,它非常逻辑和正交,只是 python 的方式)。
Yes, it seems surprising in the begining, but it is the way python works, as said in other answers. Three years of python without being slashed by this? You are lucky, very lucky. If I were you I'd check sensitive past code for little animals...
Be also careful with function calls:
def func(list=[])
has a similar behavior, that can be surprising.And, if possible, plug a pylint parse in your commit hooks. Or at least run pylint sometime on your code, it is very instructive, and would probably have told you about this trick (which is not a trick, in fact, it is very logic and orthogonal, just the python way).
您将类属性与实例属性混淆了。在第一个示例中,只有类属性
a
和b
,但在第二个示例中,还有具有相同名称的实例属性。如果没有实例属性,Python 似乎会将对属性的引用从实例传递到类(我今天学到了新东西!)。
您可能会发现这段代码很有启发:
You're confusing a class attribute with an instance attribute. In your first example, there are only the class attributes
a
andb
, but in the second you also have instance attributes with the same names.It appears that Python will pass through references to an attribute from an instance to a class if there is not instance attribute (I learned something new today!).
You may find this code instructive: