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

时间:2011-10-26 14:08:19

标签: python python-2.7 class-instance-variables

我有一个Python类,其class属性设置为None以外的其他类。创建新实例时,对该属性所做的更改会在所有实例中持续存在。

以下是一些能够理解这一点的代码:

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

 foo = Foo()
 foo.a.append('item')
 foo.b = 5

使用foo.a返回['item']foo.b会返回5,正如人们所期望的那样。

当我创建新实例时(我们称之为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返回[]bar.b返回2foo.a返回['item']foo.b返回5 }。

这是假设的工作原理吗?在我编写Python的3年里,我显然从未遇到过这个问题,并希望得到一些澄清。我也无法在文档中的任何地方找到它,所以如果可能的话,给我一个很好的参考。 :)

4 个答案:

答案 0 :(得分:7)

是的,这就是应该如何运作的。

如果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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:1)

是的,在开始时似乎令人惊讶,但正如其他答案中所述,这是python的工作方式。三年的蟒蛇没有被这个削减?你很幸运,非常幸运。如果我是你,我会检查敏感的过去代码中的小动物......

对函数调用也要小心:def func(list=[])有类似的行为,这可能会令人惊讶。

并且,如果可能的话,在提交挂钩中插入一个pylint解析。或者至少在你的代码上运行pylint,它非常有启发性,并且可能已经告诉过你关于这个技巧(这不是技巧,事实上,它是非常逻辑和正交的,只是python方式)。

答案 3 :(得分:0)

您将class属性与实例属性混淆。在第一个示例中,只有类属性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