在这篇文章中,我们来介绍一下super。相信大部分人都是这样使用super的;
<code class="language-python"># 就是我有一个 class 比如说是 Male,然后继承另外一个 class 比如是 Person,然后我在这个 Male 也就是它的子类的 init 函数里面用 super().__init__() 来调用它父类的初识化函数 from objprint import op class Person: def __init__(self, name): self.name = name class Male(Person): def __init__(self, name): super().__init__(name) self.gender = "male" m = Male('xiaoyang') op(m) # 输出:
我们在常用super的时候,通常认为super是一个方法或者函数,但其实super是一个严肃的类,它是一个内置的名字,然后super()不调用函数,super()是创建一个超级对象
>>> type(super)
虽然我们更常用的是括号内不带任何内容的super(),但是完整版的super应该有两个参数,第一个参数是一个类型,也就是一个类,第二个参数是一个类型或者是一个,其中第二个参数决定这个函数绑定到哪个类或类,第二个参数决定使用哪个mro,第一个参数决定从mro链上的哪个类开始查找。,例如;
from objprint import op
class Person:
def __init__(self, name):
self.name = name
class Male(Person):
def __init__(self, name):
# super().__init__(name)
super(Male, self).__init__(name)
self.gender = "male"
m = Male('xiaoyang')
op(m)
# 输出:
# 其实我们看刚才的 super().__init__(name) 它是等价于 super(Male, self).__init__(name) 的。
那么这个super(Male, self)就做了这样的事情。首先需要从self中获取mro,然后他会找到第一个,也就是mro中Male的位置,目前在Male的情况下,就是第一个(Male)。接下来他会开始寻找Male后面的类,然后它首先找到的是,然后看里面有没有这个函数,然后发现有这个函数,然后把这个绑定到self。这里可以理解为这个函数传入的self就是super中的self,也就是说。(self,name) 这行代码等价于 super(Male, self).(name) 这行代码。
为什么不直接使用 .(self,name) 有几个原因:
未来可能会改变基类的名称,甚至是继承方式。在这种情况下,如果您使用 super,则无需担心任何事情。它应该会自动跟随这个mro来找到正确的类,但是用这个如果要修改命名的类,它更容易导致错误。事实上,super 是动态的。他会根据self的mro进行搜索,传入的就是self。它是动态的,也就是说在同一个函数中。,我使用 super 来获得不同的类而不改变函数。
让我们看一下这个例子:
from objprint import op
class Animal:
def __init__(self, age):
self.age = age
class Person(Animal):
def __init__(self, age, name):
super().__init__(age)
self.name = name
class Male(Person):
def __init__(self,age, name):
# super(Male, self).__init__(age, name)
super(Person, self).__init__(age, name)
self.gender = "male"
m = Male(18, 'xiaoyang')
op(m)
如果你在Male super(Male, self).(age, name)中正常使用,那么它会正常初始化一切,它会访问这个,然后它会访问,最后这个就完成了Male。
那么如果你改成super(, self).(age, name),那么就会报错,因为我们在使用super(, self)的时候,self的mro链是Male然后,第一个参数It是因为是,所以他会从后面的类开始,也就是有一个函数,但是参数age只有一个,所以我们传入age名字的时候,是错误的,那么我们只需要设置它改为只传入一个年龄,如:super(, self).(age),也跳过。
总结一下 super 的两个参数分别是第一个类型和第二个类型或者分别决定的:
第一个仅确定从何处开始查找 mro 链
二是决定使用这个函数的对象和mro
super 不仅仅用在类中,它可以在任何地方使用,只要我给出第二个参数或类,从哪里开始寻找第一个参数,我可以使用它的功能,例如:
# 那这里的话就是从 m 这个 object 的 mro 上寻找 Male 后面开始的 __init__ 函数,这样实际上就找到了 Person 的 __init__ 函数,然后再用 Person 的 __init__ 函数对 m 这个 object 做初始化
from objprint import op
class Animal:
def __init__(self, age):
self.age = age
class Person(Animal):
def __init__(self, age, name):
super().__init__(age)
self.name = name
class Male(Person):
def __init__(self,age, name):
super(Person, self).__init__(age)
self.gender = "male"
m = Male(18, 'xiaoyang')
op(m)
print("----------------------")
super(Male, m).__init__(20, "xiaoyang")
op(m)
# 输出:
----------------------
暂无评论内容