为何super()操作基类类变量时行为不符合预期?
问题:为何使用super()调用方法后类变量计数未更新?
我正在学习类的相关知识,想要实现一个记录MyClass类实例数量的计数器:
class ObjectCounter: # I want this to count the number of objects in each class myclass_obj_count = 0 class MyClass(ObjectCounter): def __init__(self): super().myclass_obj_count += 1 # AttributeError: 'super' object has no attribute 'myclass_obj_count' m1 = MyClass() m2 = MyClass() m3 = MyClass() print(ObjectCounter.myclass_obj_count)
这段代码报错后,我找到一段直接使用类名操作类变量的可行代码,但我想理解super()的工作原理,于是尝试了另一种写法:
class ObjectCounter: # I want this to count the number of objects in each class myclass_obj_count = 0 def add_myclass(self): self.myclass_obj_count += 1 class MyClass(ObjectCounter): def __init__(self): super().add_myclass() my_class_1 = MyClass() my_class_2 = MyClass() my_class_3 = MyClass() print(ObjectCounter.myclass_obj_count) # expected output: 3
但最终输出为0而非预期的3,请问这是为什么?
解答
第一次报错的原因
super()返回的是一个特殊的代理对象,它的核心作用是调用父类的方法,而非直接操作类变量。当你尝试super().myclass_obj_count += 1时,Python会尝试从super对象中读取目标属性,但super对象本身并不持有该属性(它仅代理访问父类的属性,但赋值操作无法通过这个代理直接作用于父类的类变量),因此抛出AttributeError。
第二次输出为0的核心问题
问题出在add_myclass方法里的self.myclass_obj_count += 1:
- 通过
self访问属性时,Python会优先在当前实例的命名空间中查找属性;找不到的情况下,才会去类、父类的命名空间中查找。 - 执行
self.myclass_obj_count += 1时,Python先读取到父类ObjectCounter的类变量myclass_obj_count(值为0),计算得到1后,会把这个值赋值给当前实例的新属性——也就是给实例创建了一个同名的实例变量,完全不会修改父类的类变量。 - 最终父类的
myclass_obj_count始终是初始值0,而每个MyClass实例都有自己独立的myclass_obj_count实例变量,值为1。
正确的实现方式
如果要实现子类实例的计数,需要直接操作类的命名空间而非实例的:
class ObjectCounter: def add_instance(self): # 通过type(self)获取当前实例所属的类,修改对应类的类变量 type(self).instance_count += 1 class MyClass(ObjectCounter): # 每个子类定义自己的类变量用于计数 instance_count = 0 def __init__(self): super().add_instance() my_class_1 = MyClass() my_class_2 = MyClass() my_class_3 = MyClass() print(MyClass.instance_count) # 输出:3
这种写法可以让每个子类独立维护自己的实例计数,父类仅提供通用的计数更新逻辑。
内容的提问来源于stack exchange,提问作者h4zard
相关产品推荐
相关产品推荐

