Python 具有非None类属性的类的新实例?
我有一个Python类,它的class属性设置为除Python 具有非None类属性的类的新实例?,python,python-2.7,class-instance-variables,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
之外的其他属性。创建新实例时,对该属性所做的更改将在所有实例中保持不变
这里有一些代码可以解释这一点:
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
时,然后将它们设置为\uuuu init\uuuu
中的任意值,如下所示:
class Foo(object):
a = None
b = None
def __init__(self):
self.a = []
self.b = 2
使用bar.a
返回[]
和bar.b
返回2
,而foo.a
返回['item']
和foo.b
返回5
这就是它的工作原理吗?在编写Python的三年时间里,我显然从未遇到过这个问题,我希望得到一些澄清。我在文档中的任何地方都找不到它,所以如果可能的话,给我一份参考资料会很好。:) 是的,它应该是这样工作的 如果
a
和b
属于Foo
的实例,那么正确的方法是:
class Foo(object):
def __init__(self):
self.a = []
self.b = 2
以下内容使a
和b
属于类本身,因此所有实例共享相同的变量:
class Foo(object):
a = []
b = 2
当您混合使用这两种方法时——正如您在第二个示例中所做的那样——这并没有添加任何有用的内容,只会导致混淆
值得一提的一个警告是,当您在第一个示例中执行以下操作时:
foo.b = 5
您没有更改
Foo.b
,而是向Foo
添加了一个全新的属性,即“阴影”Foo.b
。执行此操作时,bar.b
和Foo.b
都不会更改。如果随后执行del foo.b
,则会删除该属性,foo.b
将再次引用foo.b您将类属性与实例属性混淆。在第一个示例中,只有类属性a
和b
,但在第二个示例中,还有同名的实例属性
如果没有实例属性,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
是的,这正是你应该期待的。在类上定义变量时,这些属性将附加到类,而不是实例。您可能不会总是注意到,当您为实例上的属性赋值时,该实例会拾取新值,从而屏蔽class属性。就地修改的方法,如list.append
不会为实例提供新属性,因为它们只是修改现有对象,而现有对象恰好是类的属性
每当一个类的每个实例都应该有自己的、唯一的属性值时,您通常应该在\uuuu init\uuuu
方法中设置该值,以确保每个实例的值都不同
只有当一个类的属性有一个合理的默认值,并且该值是一个不可变的类型(不能就地修改),例如int
或str
,您才应该在该类上设置属性。是的,一开始看起来很奇怪,但正如其他答案中所说,python就是这样工作的。三年的python都没有被它砍掉?你很幸运,非常幸运。如果我是你,我会检查小动物过去的敏感代码
还要注意函数调用:def func(list=[])
也有类似的行为,这可能会令人惊讶
如果可能的话,在提交钩子中插入pylint解析。或者至少在你的代码上运行pylint,这很有启发性,可能会告诉你这个技巧(这不是一个技巧,事实上,它是非常逻辑和正交的,只是python的方式)。啊,我明白了!直到现在我才意识到类和实例属性之间的区别!我总是假设类属性是在类本身中定义的(例如示例),并且会使用类似foo.c=2
(一个动态定义,如果您愿意的话)。有道理!谢谢谢谢正如我在上面的回答中所说,我显然不知道类和实例属性之间的区别!我想这可能是自学成才和缺乏耐心的一个警告谢谢我肯定把这两个人搞糊涂了!