类和实例属性
我了解到,Python中的类属性就像C++中的静态数据成员。不过,我在尝试以下代码时感到困惑:
>>> class Foo:
... a=1
...
>>> f1=Foo();
>>> f2=Foo()
>>> f1.a
1
>>> f1.a=5
>>> f1.a
5
>>> f2.a
1
难道f2.a不应该也等于5吗?
如果a被定义为一个列表而不是一个整数,结果就符合预期了:
>>> class Foo:
... a=[]
...
>>> f1=Foo();
>>> f2=Foo()
>>> f1.a
[]
>>> f1.a.append(5)
>>> f1.a
[5]
>>> f2.a
[5]
我查看了 类属性和实例属性有什么区别?,但这并没有解答我的疑问。
有没有人能解释一下为什么会有这个区别?
6 个回答
在编程中,有时候我们会遇到一些问题,想要找到解决办法。比如说,有人可能在使用某个工具或库的时候,发现它的某个功能不太好用,或者出现了错误。这时候,大家通常会去一个叫StackOverflow的网站上提问,看看有没有人遇到过类似的问题,或者有没有人能给出解决方案。
在这个网站上,很多程序员会分享他们的经验和解决办法。你可以在这里找到很多关于编程的讨论,甚至是一些很具体的技术问题的答案。通过这些讨论,初学者可以学习到很多实用的知识,帮助他们更好地理解编程的世界。
总之,StackOverflow是一个很好的资源,特别是对于那些刚开始学习编程的人来说,能够在这里找到很多有用的信息和帮助。
>>> class Foo:
... a=1
...
>>> f1=Foo()
>>> f2=Foo()
>>> f1.a # no instance attribute here in f1, so look up class attribute in Foo
1
>>> f1.a=5 # create new instance attribute in f1
>>> f1.a # instance attribute here. Great, let's use this.
5
>>> f2.a # no instance attribute in f2, look up class attribute in Foo
1
>>>
>>> class Foo:
... a=[]
...
>>> f1=Foo()
>>> f2=Foo()
>>> f1.a # no instance attribute - look up class attribute in Foo
[]
>>> f1.a.append(5) # no instance attribute, modify class attribute in-place
>>> f1.a # no instance attribute - look up class attribute in Foo
[5]
>>> f2.a # same here
[5]
在Python中,类属性和对象属性是存放在不同的字典里的。对于对象f1
,你可以通过f1.__class__.__dict__
和f1.__dict__
来访问它们。执行print f1.__class__ is Foo
会输出True
,这表示f1
是类Foo
的一个实例。
当你想要访问一个对象的属性时,Python会先在这个对象的字典里查找。如果找不到,它就会去类的字典里查找(如果有继承关系,还会继续往上查找)。
当你给f1.a
赋值时,其实是在f1
的对象字典里添加了一条记录。之后再查找f1.a
时,就能找到这条记录。而查找f2.a
时,仍然会找到类属性,也就是类字典里的那条记录。
如果你想把f1.a
的值恢复成1
,可以通过删除它来实现:
del f1.a
这样会把f1
对象字典里的a
这一条记录删除,之后再查找时就会继续到类字典里去找。所以,之后执行print f1.a
会输出1
。
在你的第二个例子中,你做的事情和第一个例子不一样。在第一个例子里,你是给 f1.a
赋了一个新值:
f1.a = 5
而在第二个例子中,你只是扩展了一个列表:
f1.a.append(5)
这样并不会改变 f1.a
指向的内容。如果你这样做:
f1.a = [5]
你会发现这和你的第一个例子表现得是一样的。
再看看这个例子:
>>> f1=Foo()
>>> f2=Foo()
>>> Foo.a = 5
>>> f1.a
5
>>> f2.a
5
在这个例子中,我们实际上是在改变 类 属性的值,并且这个变化在所有类的实例中都是可见的。当你输入:
f1.a = 5
你是在用一个 实例 属性覆盖 类 属性。