十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
这篇文章我们来介绍一下 super,我相信大部分的人使用 super 都是使用这种方式;
创新互联公司专注为客户提供全方位的互联网综合服务,包含不限于网站设计制作、成都做网站、革吉网络推广、微信小程序开发、革吉网络营销、革吉企业策划、革吉品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们最大的嘉奖;创新互联公司为所有大学生创业者提供革吉建站搭建服务,24小时服务热线:18980820575,官方网址:www.cdcxhl.com
# 就是我有一个 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 是一个正儿八经的 class,它是一个内置内的名字,然后 super() 并不是调用了一个函数 ,super() 是建立 了一个 super 的对象
>>> type(super)
尽管我们更常用的是 super() 括号里面什么都没有,但是 super 的完整版它里面应该是有两个参数,第一个参数是一个 type 也就是一个 class,第二个参数是一个 type 或者是一个 object,其中第二个参数决定了这一个函数绑定到那个 object 或者 class 上,同时第二个参数决定了使用那个 mro,而第一个参数决定了在 mro 链上 从哪个class 开始往后找,例如;
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 这个 object 里面拿到 mro,然后他会找到第一个 argument,也就是 Male 在 mro 里所处的位置,那在当前的情况下 Male 就是最开始的那个(Male Person object)接下来他会从 Male 后面的那个 class 开始找,那它第一个找到的就是 Person,然后它就看Person 里面有没有__init__
这个函数,然后发现有这个函数,然后它在把这个__init__
绑定到 self 上,在这里可以理解为这个 Person 的__init__
函数传进去的这个 self 就是 super 里面的这个 self,也就是说Person.__init__(self,name)
这行代码等价于 super(Male, self).__init__(name)
这行代码。
至于为什么不直接使用Person.__init__(self,name)
是有几个原因:
在来看这个示例:
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).__init__(age, name)
,那么它就会正常的初始化所有的东西,它会访问这个 Person 的 __init__
,然后 Person 的__init__
会访问 Animal 的__init__
,最后就完成了这个 Male。
那如果把它改成super(Person, self).__init__(age, name)
,那么就会报错,因为当我们使用 super(Person, self)
的时候,self 的 mro 链是 Male Person Animal 然后是 object,那第一个参数它由于是 Person,所以他会从 Person 后面的那个 class 也就是 Animal 开始找,那 Animal 是有__init__
函数的,但是 Animal 的 __init__
只有一个参数 age,所以当我们传入 age name 的时候那就错了,这时候就只需要将它改成只传进去一个 age 如: super(Person, self).__init__(age)
就可以了,同时也跳过了 Person。
总结 super 的两个参数也就是第一个 type 和第二个 type 或者 object 分别决定了什么:
第一个只决定了在 mro 这个链上从哪里开始找
第二个是决定使用这个函数的对象和 mro
super 并不是只能在 class 里面使用的,它可以在任何一个地方使用,我只要给定 第二个参数 object 或者 class ,在给定第一个参数从哪里开始找,我就能使用它的函数,例如:
# 那这里的话就是从 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)
# 输出:
----------------------