
在python中,super()函数提供了一种在子类中调用父类(或兄弟类)方法和访问父类属性的方式,它遵循mro(method resolution order,方法解析顺序)规则。super()主要用于以下场景:
需要强调的是,super()是基于类层级的查找机制,它关注的是类的方法和类属性,而不是特定实例的实例属性。
与类属性不同,实例属性(如self.b)是与类的特定实例相关联的数据。它们通常存储在实例的__dict__字典中。这意味着:
让我们通过一个具体的例子来理解为何尝试通过super()访问实例属性会导致AttributeError。
考虑以下Python代码:
立即学习“Python免费学习笔记(深入)”;
class P:
a = 10 # 类属性
def __init__(self):
self.b = 20 # 实例属性
class C(P):
a = 888 # 子类的类属性,覆盖了P.a
def __init__(self):
self.b = 999 # 子类的实例属性,会覆盖父类的self.b
super().__init__() # 调用父类的构造函数
print(f"通过super()访问类属性 'a': {super().a}")
print(f"尝试通过super()访问实例属性 'b': {super().b}") # 导致AttributeError
# 创建C的实例
c = C()运行上述代码,输出结果如下:
通过super()访问类属性 'a': 10
Traceback (most recent call last):
File ".\test.py", line 21, in <module>
c = C()
File ".\test.py", line 19, in __init__
print(f"尝试通过super()访问实例属性 'b': {super().b}")
AttributeError: 'super' object has no attribute 'b'分析:
print(f"通过super()访问类属性 'a': {super().a}"):
print(f"尝试通过super()访问实例属性 'b': {super().b}"):
核心原因在于:super()关注的是类的定义(类属性、方法),而不是特定实例的数据(实例属性)。实例属性始终通过self来访问。
既然实例属性是存储在实例本身上的,那么在继承体系中,我们应该如何正确地管理和访问它们呢?
1. 实例属性的赋值顺序:
在子类的__init__方法中,通常建议先调用super().__init__(),以确保父类的初始化逻辑(包括实例属性的设置)先执行。然后,子类再进行自己的初始化或覆盖父类的实例属性。
class P:
def __init__(self):
self.b = 20
print(f"P.__init__ 初始化 self.b = {self.b}")
class C(P):
def __init__(self):
# 推荐:先调用父类的构造函数
super().__init__()
print(f"C.__init__ 调用 super().__init__() 后,self.b = {self.b}")
# 然后,子类可以修改或设置自己的实例属性
self.b = 999
print(f"C.__init__ 设置 self.b = {self.b}")
c = C()
print(f"实例c的最终 self.b = {c.b}")
# 访问实例属性总是通过实例本身
# print(super().b) # 依然会报错
print(f"通过实例访问 self.b: {c.b}")输出:
P.__init__ 初始化 self.b = 20 C.__init__ 调用 super().__init__() 后,self.b = 20 C.__init__ 设置 self.b = 999 实例c的最终 self.b = 999 通过实例访问 self.b: 999
从上述输出可以看出,self.b在整个过程中都是同一个实例属性,其值随着赋值操作而改变。
2. 区分父类和子类的实例属性(如果需要):
如果确实需要父类和子类拥有“各自版本”的实例属性,那么它们必须使用不同的名称。但在大多数情况下,实例属性在整个继承链中是共享和演进的。
class P:
def __init__(self):
self.p_specific_attribute = "来自父类P"
class C(P):
def __init__(self):
super().__init__()
self.c_specific_attribute = "来自子类C"
c_instance = C()
print(c_instance.p_specific_attribute)
print(c_instance.c_specific_attribute)理解super()与实例属性之间的根本区别,是编写健壮、可维护的Python面向对象代码的关键。记住,super()是关于类层次结构和MRO的,而实例属性是关于特定对象的数据状态的。
以上就是深入理解Python中super()与实例属性的访问机制的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号