类和实例属性

8 投票
6 回答
5279 浏览
提问于 2025-04-17 03:03

我了解到,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 个回答

7

在编程中,有时候我们会遇到一些问题,想要找到解决办法。比如说,有人可能在使用某个工具或库的时候,发现它的某个功能不太好用,或者出现了错误。这时候,大家通常会去一个叫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]
10

在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

8

在你的第二个例子中,你做的事情和第一个例子不一样。在第一个例子里,你是给 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

你是在用一个 实例 属性覆盖 属性。

撰写回答