python super使用

文章讨论了Python中多继承时`__init__`方法的调用规则,强调了使用`super`关键字正确初始化父类的重要性,并揭示了菱型问题(即不同继承顺序导致的值重置问题)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

class Base1():
    def __init__(self, name):
        self._name = name
        print("name", self._name)
    
    def my_func(self):
        print(self._name)
        

class Base2():
    def __init__(self, age):
        self._age = age
        print("age",self._age)
        
    
    def my_func(self):
        print(self._age)
        
        
class Son(Base1, Base2):
    
    def __init__(self, name, age):
        # 子类多继承时,super参数时子类时,制有第一个继承基类第一个类Base1被初始化
        super(Son, self).__init__(age)
        
        # 初始化Base2
        super(Son, self).__init__(name)
        

    def my_func(self):
        print("son")
        


c = Son("ls", 20)
c.my_func() 
# output:
# name 20
# name ls
# son


class Son1(Base1, Base2):
    
    def __init__(self, name, age):
        
        # super参数填写父类时,按继承顺序只能Base1可以被初始化
        # super(Base1, self).__init__(name) # ok
        # super(Base2, self).__init__(age) # error

        # 不是顺序初始化,报错
        # super(Base2, self).__init__(name) # error
        # super(Base1, self).__init__(age)  # not reach
        
        # 直接使用基类类名调用__init__(), 正确执行
        Base1.__init__(self, name) 
        Base2.__init__(self, age)
        
        
    def my_func(self):
        print("son")

c1 = Son1("ls", 20)
c1.my_func()
# output:
# name ls
# 20
# son



class Son2(Base1, Base2):
    
    def __init__(self, name, age):
        # 子类多继承时,super无参数时,只有第一个继承基类第一个类Base1被初始化
        super().__init__(name)
        super().__init__(age)
        
        # supper加子类名,效果同上
        # super(Son2,self).__init__(name)
        # super(Son2,self).__init__(age)
        
    def my_func(self):
        print("son")
        
c1 = Son2("ls", 20)
c1.my_func()
# output:
# name ls
# name 20
# son

总结:多继承,使用基类名称调用__init__进行初始化父类
# 菱型问题
class MyBaseClass:
    def __init__(self, value):
        self.value = value

class TimesFive(MyBaseClass):
    def __init__(self, value):
        MyBaseClass.__init__(self, value)
        self.value *= 5

class PlueTwo(MyBaseClass):
    def __init__(self, value):
        MyBaseClass.__init__(self, value)
        self.value +=2
        
        
class Test(TimesFive, PlueTwo):
    def __init__(self, value):
        TimesFive.__init__(self, value)
        PlueTwo.__init__(self, value)
        
test = Test(5)
print(test.value)
# output: 7, 而不是预想的27
# 因为PlueTwo后初始化时,调用MyBaseClass.__init__(self, value)父类
# 初始化有对value重新初始化了为5,所以为7

class TimesFiveCorrect(MyBaseClass):
    def __init__(self, value):
        super(TimesFiveCorrect, self).__init__(value)
        self.value *= 5
class PlusTwoCorrect(MyBaseClass):
    def __init__(self, value):
        super(PlusTwoCorrect, self).__init__(value)
        self.value += 2


class TestSuper(TimesFiveCorrect, PlusTwoCorrect):
    def __init__(self, value):
        super(TestSuper, self).__init__(value)
        

test1 = TestSuper(5)    
print(test1.value) # 35而不是预想的27,因为父类实例化规则
# 是根据MRO标准规则,使用mro函数查看初始化树
from pprint import pprint
pprint(TestSuper.mro())
# output:
# [<class '__main__.TestSuper'>,
#  <class '__main__.TimesFiveCorrect'>,
#  <class '__main__.PlusTwoCorrect'>,
#  <class '__main__.MyBaseClass'>,
#  <class 'object'>]
# TestSuper并没有真正执行,先到根MyBaseClass,再由根到TestSuper
# 所以执行结果是(5+2) * 5 = 35
### Python中 `super()` 函数的正确用法 #### 基本定义 `super()` 是 Python 提供的一个内置函数,主要用于调用父类(超类)的方法。通过这种方式可以实现对父类方法的有效重用,在单继承或多继承情况下尤其重要[^2]。 --- #### 单继承中的使用 在单继承结构下,`super()` 可以用来简化对父类方法的调用过程。下面是一个简单的例子: ```python class Parent: def greet(self, name): print(f"Hello {name} from Parent!") class Child(Parent): def greet(self, name): print("Child says:", end=" ") super().greet(name) # 调用父类的 greet 方法 child_instance = Child() child_instance.greet("Alice") # 输出: Child says: Hello Alice from Parent! ``` 上述代码展示了如何利用 `super()` 来调用父类的 `greet` 方法,而无需显式指定父类名称[^1]。 --- #### 多重继承中的 MRO (Method Resolution Order) 在多重继承的情境下,`super()` 遵循一种称为 **C3线性化算法** 的机制来决定方法解析顺序(MRO)[^5]。这意味着即使有复杂的多层继承关系,`super()` 也能按预定顺序依次调用各个父类的相关方法。 考虑如下示例: ```python class A: def greet(self): print("A") class B(A): def greet(self): print("B", end=", ") super().greet() class C(A): def greet(self): print("C", end=", ") super().greet() class D(B, C): def greet(self): print("D", end=", ") super().greet() d_instance = D() d_instance.greet() # 输出: D, B, C, A print(D.mro()) # 显示类 D 的 MRO 列表 ``` 在此案例中,`super()` 自动遵循由左至右深度优先的原则执行各层次上的 `greet` 方法调用[^3]。 --- #### 参数化的 `super()` 尽管现代 Python 版本支持无参形式的 `super()` 使用方式,但在某些特殊场合仍需采用带参数版本。其语法为 `super(class_name, instance)` 或者 `super(current_class, subclass)` 形式。例如: ```python class BaseClass: def hello(self): print('Base') class SubClass(BaseClass): def hello(self): super(SubClass, self).hello() # 显式指明当前类及其实例 print('Sub') sub_obj = SubClass() sub_obj.hello() # 输出: Base\nSub ``` 这种写法虽然冗余却更清晰地表明了上下文关联,特别适用于跨模块复杂场景下的调试分析阶段[^4]。 --- #### 总结 - 对于简单情况推荐直接运用不加任何额外参数的 `super()` 表达式; - 如果涉及多重继承,则依赖内部计算得出的最佳路径完成相应操作; - 当需要兼容旧版程序或者增强可读性时可以选择带有具体类别指示符的形式。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值