super()干了啥
super()继承
转自:https://www.cnblogs.com/silencestorm/p/8404046.html
class Base(object):
def __init__(self):
print("Enter Base")
print("Leave Base")
class A(Base):
def __init__(self):
print('Enter A')
super(A, self).__init__() # 等同于python3: super().__init__()
print('Leave A')
class B(Base):
def __init__(self):
print('Enter B')
super(B, self).__init__()
print('Leave B')
class C(A,B):
def __init__(self):
print('Enter C')
super(C, self).__init__()
print('Leave C')
C()
print(C.mro())
"""
Enter C
Enter A
Enter B
Enter Base
Leave Base
Leave B
Leave A
Leave C
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]
"""
每一个类,都有一个 MRO(Method Resolution Order) 列表。这是python 在多继承时,搜索属性和方法时的顺序。可以通过 class.mro()
或 obj.__class__.mro()
来查看。
>>> C.mro()
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]
super()
的原理:
def super(class, instance):
mro = instance.__class__.mro() # 获取 self 的类的 mro 列表
return mro[mro.index(class)+1] # 返回显式指定的类 class 的下一个父类
所以上面代码执行顺序:
line 24: 实例化 C 类
line 21: 查找 self 实例的 mro 中位于 C 类之后的那个类,即 A 类,找到后执行它的 __init__ 方法(注意此时类 A 的 __init__ 方法已经绑定给了 self 实例,即 C 类的实例。换句话说,self 实例会作为参数传递给 A.__init__ 方法)。
line 9: 此时 super(A, self).__init__() 中的 self,代表的是 C类实例,所以下一步查找到 C 类 mro 中的类A后面的是类 B,执行 B.__init(self) 方法
line 15: 此时的 self 还是 C 实例,所以根据mro顺序,下一步执行mro中的 Base类
简而言之,super(A, self)
可以按照 mro 顺序,找到类 A 后面的类,然后将那个类的某个方法,绑定给 self
实例,可以让实例调用父类的方法。
三种继承父类方法的写法:
类名.方法名(self, 参数) # 直接调用类 A 的某个方法,此时要将 self 作为参数传递给该方法
super().方法名(参数) # 自动查找当前类的第一个父类的某个方法
super(A, b).方法名(参数) # 自动查找当前实例 b 的类的 MRO 列表中类 A 之后的那个类,并调用其方法
三种方法的区别:
类名.方法名(self, 参数)
这种方法是最原始的方法。它可以将当前self
实例和类的方法绑定起来,然后调用该方法,因此需要手动将self
实例作为参数传递给方法。super().方法名(参数)
更推荐的写法,它会自动从当前实例所属类的mro
中查找下一个父类,并调用该父类的方法,当你调用super().方法名
时,super()
会自动关联到当前类和当前实例(即 self),并确保方法调用时正确传递 self。因此不需要手动传递self
参数给方法,super 默认已经给方法传递了 self。 其实相当于调用了父类.方法(self, 参数)
super(A, obj).方法名(参数)
它是较老的写法,同时也是更灵活的写法:它可以指定从obj
的类的 MRO 列表中,查找类 A 之后的那个类,并调用该类的方法,也就是它可以跳过 MRO 列表中的某些类,从而指定使用某个父类的方法。它也不需要手动传递 self 参数给方法强调一点:super() 可以调用父类的任意方法,而不仅仅是
__init__
这种特殊方法。其他事项:对于
__new__(cls, *args, **kwargs)
方法,其中的参数cls
代表的是一个类,实例化一个类时,不需要手动传递这个参数,但是如果继承父类的此方法,就需要手动传递,因为需要让父类知道给哪个类创建实例化对象,比如:class Base(object): def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Base, cls).__new__(cls) # 需要把 cls 作为参数传递给父类的 __new__ 方法 return cls._instance
class Base(object):
def __init__(self, name):
print("Enter Base")
super().__init__() # 第一种:直接继承使用当前类之后的父类的 __init__() 方法,这里是 object.__init__() 方法
print("Leave Base")
class A(Base):
def __init__(self, name):
print('Enter A')
super(Base, self).__init__() # 第二种:指定从 Base 之后查找父类,并调用该父类的方法(这种方式可以跳过 MRO 列表中的某个父类,这里跳过了父类 Base,而是使用 Base 之后的类 object 的 __init__ 方法)
print('Leave A')
class B(A):
def __init__(self, name):
Base.__init__(self, name) # 第三种: 直接指定使用某个类的方法(这种用法,必须要将 self 作为参数传递到方法中,目的是将 self 实例和该方法绑定)
super(A, self).__init__(name) # 等效于上一行:这里跳过了父类 A,下一个父类刚好是 Base
self.name = name
b = B("haha")