Python中的类变量与实例变量问题

3 投票
2 回答
521 浏览
提问于 2025-04-16 10:09

当我有这个类的时候,变量 'value' 是一个类变量。

class Hello:
    value = 10
    def __init__(self):
        print 'init'

我有一个对象 'h',我可以通过 Hello.value 和 h.value 都得到相同的值 '10'。

h = Hello()
print Hello.value
print h.value

当我运行这个命令时,

h.value = 20

我得到的值是 '10' 和 '20',当我运行它们的时候。

print Hello.value
print h.value

这是为什么呢?

  • 问题1:为什么 'print h.value' 会打印出 Hello.value 的值,而不是报错?
  • 问题2:h.value = 20 是不是引入了一个新的变量,和 'self.value = 20' 类似?
  • 问题3:有没有办法防止创建实例变量(或者防止运行代码 'h.value = 20')?

相关问题:

2 个回答

4

当Python查找o.attr时,它会先检查这个对象实例,然后检查它的类,再接着检查基类,依此类推。这个过程适用于方法和数据属性(也就是说,数据属性和代码属性没有区别)。

在赋值的时候,值总是被赋给实例。所以:

  • A1. 因为它会回退到类(这是必须的,否则方法就无法正常工作)。

  • A2. 是的,它会这样做。

  • A3. 你可以定义一个__setattr__方法来抛出一个异常。

4

这是Python中属性查找的工作原理:

  1. 如果在一个实例的字典里找不到某个属性,Python会去它的类的字典里找,如果还找不到,就会继续在基类的字典里查找。

  2. 如果你给实例的属性赋值,这个操作只会影响这个实例本身——也就是说,如果这个属性已经存在于实例里,它会被更新;如果不存在,就会在这个实例的字典里创建一个新的属性。

如果你不喜欢这种行为,可以重写 __setattr__() 方法,按照你的想法来处理属性的设置——比如,如果你不想允许创建实例属性,可以抛出一个错误。你也可以通过在类中添加 __slots__ = [] 来实现这一点。

撰写回答