具有非 None 类属性的类的新实例?

发布于 2024-12-11 21:39:11 字数 945 浏览 1 评论 0原文

我有一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

挖个坑埋了你 2024-12-18 21:39:11

是的,这就是它应该如何工作的。

如果ab属于Foo实例,那么正确的做法是

class Foo(object):
   def __init__(self):
     self.a = []
     self.b = 2

:使 ab 属于类本身,因此所有实例共享相同的变量:

class Foo(object):
   a = []
   b = 2

当您混合使用这两种方法时 - 正如您所做的那样在你的第二个例子中——这不会添加任何有用的东西,只会引起混乱。

值得一提的一个警告是,当您在第一个示例中执行以下操作时:

foo.b = 5

您没有更改 Foo.b,而是向 foo 添加了一个全新的属性,该属性“遮蔽“ Foo.b.当您执行此操作时,bar.bFoo.b 都不会改变。如果您随后执行 del foo.b,则会删除该属性,并且 foo.b 将再次引用 Foo.b

Yes, this is how it is supposed to work.

If a and b belong to the instance of Foo, then the correct way to do this is:

class Foo(object):
   def __init__(self):
     self.a = []
     self.b = 2

The following makes a and b belong to the class itself, so all instances share the same variables:

class Foo(object):
   a = []
   b = 2

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:

foo.b = 5

you are not changing Foo.b, you are adding a brand new attribute to foo that "shadows" Foo.b. When you do this, neither bar.b nor Foo.b change. If you subsequently do del foo.b, that'll delete that attribute and foo.b will once again refer to Foo.b.

你的背包 2024-12-18 21:39:11

是的,这正是您所期望的。当您在类上定义变量时,这些属性将附加到类,而不是实例。您可能并不总是注意到,当您分配给实例上的属性时,实例会获取新值,从而屏蔽类属性。 就地修改的方法(例如list.append)不会为实例提供新属性,因为它们只是修改现有对象,而该对象恰好是该类的属性。

任何时候,类的每个实例都应该有自己唯一的属性值,通常应该在 __init__ 方法中设置该值,以确保每个实例的值都不同。

仅当类具有具有合理默认值的属性,并且该值属于不可变类型(无法就地修改)时,例如 intstr ,您是否应该在类上设置属性。

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 or str, should you set attributes on the class.

分开我的手 2024-12-18 21:39:11

是的,一开始似乎令人惊讶,但正如其他答案中所述,这就是 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).

情绪 2024-12-18 21:39:11

您将类属性与实例属性混淆了。在第一个示例中,只有类属性 ab,但在第二个示例中,还有具有相同名称的实例属性。

如果没有实例属性,Python 似乎会将对属性的引用从实例传递到类(我今天学到了新东西!)。

您可能会发现这段代码很有启发:

class Foo:
  a = 1
  b = 2

  def __init__(self):
    self.a=3

print Foo.a   # => 1
print Foo().a # => 3
print Foo.b   # => 2
print Foo().b # => 2

You're confusing a class attribute with an instance attribute. In your first example, there are only the class attributes a and b, 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:

class Foo:
  a = 1
  b = 2

  def __init__(self):
    self.a=3

print Foo.a   # => 1
print Foo().a # => 3
print Foo.b   # => 2
print Foo().b # => 2
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文