菜鸟教程 -- 学的不仅是技术,更是梦想!

Python 基础教程
(追記) (追記ここまで)

Python super() 函数

Python 内置函数 Python 内置函数


描述

super() 函数是用于调用父类(超类)的一个方法。

super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

语法

以下是 super() 方法的语法:

super(type[, object-or-type])

参数

  • type -- 类。
  • object-or-type -- 类,一般是 self

Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx :

Python3.x 实例:

classA: defadd(self, x): y = x+1print(y)classB(A): defadd(self, x): super().add(x)b = B()b.add(2)# 3

Python2.x 实例:

#!/usr/bin/python# -*- coding: UTF-8 -*-classA(object): # Python2.x 记得继承 objectdefadd(self, x): y = x+1print(y)classB(A): defadd(self, x): super(B, self).add(x)b = B()b.add(2)# 3

返回值

无。


实例

以下展示了使用 super 函数的实例:

实例

#!/usr/bin/python# -*- coding: UTF-8 -*-classFooParent(object): def__init__(self): self.parent = 'I\'m the parent.'print('Parent')defbar(self,message): print("%s from Parent" % message)classFooChild(FooParent): def__init__(self): # super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),然后把类 FooChild 的对象转换为类 FooParent 的对象super(FooChild,self).__init__()print('Child')defbar(self,message): super(FooChild, self).bar(message)print('Child bar fuction')print(self.parent)if__name__ == '__main__': fooChild = FooChild()fooChild.bar('HelloWorld')

执行结果:

Parent
Child
HelloWorld from Parent
Child bar fuction
I'm the parent.

Python 内置函数 Python 内置函数

AI 思考中...

4 篇笔记 写笔记

  1. #0

    直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)。一开始看到这句话,不太理解。

    看了这个文章后,明白了。

    我们在学习 Python 类的时候,总会碰见书上的类中有 __init__() 这样一个函数,很多同学百思不得其解,其实它就是 Python 的构造方法。

    构造方法类似于类似 init() 这种初始化方法,来初始化新创建对象的状态,在一个对象呗创建以后会立即调用,比如像实例化一个类:

    f = FooBar()
    f.init()

    使用构造方法就能让它简化成如下形式:

    f = FooBar()

    你可能还没理解到底什么是构造方法,什么是初始化,下面我们再来举个例子:

    class FooBar:
     def __init__(self):
     self.somevar = 42
    >>>f = FooBar()
    >>>f.somevar

    我们会发现在初始化 FooBar 中的 somevar 的值为 42 之后,实例化直接就能够调用 somevar 的值;如果说你没有用构造方法初始化值得话,就不能够调用,明白了吗?

    在明白了构造方法之后,我们来点进阶的问题,那就是构造方法中的初始值无法继承的问题。

    例子:

    class Bird:
     def __init__(self):
     self.hungry = True
     def eat(self):
     if self.hungry:
     print 'Ahahahah'
     else:
     print 'No thanks!'
    class SongBird(Bird):
     def __init__(self):
     self.sound = 'Squawk'
     def sing(self):
     print self.song()
    sb = SongBird()
    sb.sing() # 能正常输出
    sb.eat() # 报错,因为 songgird 中没有 hungry 特性

    那解决这个问题的办法有两种:

    1、调用未绑定的超类构造方法(多用于旧版 python 阵营)

    class SongBird(Bird):
     def __init__(self):
     Bird.__init__(self)
     self.sound = 'Squawk'
     def sing(self):
     print self.song()

    原理:在调用了一个实例的方法时,该方法的self参数会自动绑定到实例上(称为绑定方法);如果直接调用类的方法(比如Bird.__init__),那么就没有实例会被绑定,可以自由提供需要的self参数(未绑定方法)。

    2、使用super函数(只在新式类中有用)

    class SongBird(Bird):
     def __init__(self):
     super(SongBird,self).__init__()
     self.sound = 'Squawk'
     def sing(self):
     print self.song()

    原理:它会查找所有的超类,以及超类的超类,直到找到所需的特性为止。

    sme000 7年前 (2019年04月23日)
  2. #0

    yyYanis

    ysh***[email protected]

    184

    经典的菱形继承案例,BC 继承 A,然后 D 继承 BC,创造一个 D 的对象。

     ---> B ---
    A --| |--> D
     ---> C ---
    

    使用 super() 可以很好地避免构造函数被调用两次。

    # 思考题正确答案
    class A():
     def __init__(self):
     print('enter A')
     print('leave A')
    class B(A):
     def __init__(self):
     print('enter B')
     super().__init__()
     print('leave B')
    class C(A):
     def __init__(self):
     print('enter C')
     super().__init__()
     print('leave C')
    class D(B, C):
     def __init__(self):
     print('enter D')
     super().__init__()
     print('leave D')
    d = D()

    执行结果是:

    enter D
    enter B
    enter C
    enter A
    leave A
    leave C
    leave B
    leave D

    yyYanis

    ysh***[email protected]

    7年前 (2019年06月11日)
  3. #0

    没有昵称

    noe***[email protected]

    参考地址

    18

    建议自己单点调试走一遍就能理解 super 的本质。

    class A(object):
     def __init__(self):
     print("enter A")
     print(self) # this will print <__main__.D object at 0x...>
     print("leave A")
    class B(A):
     def __init__(self):
     print("enter B")
     print(self) # this will print <__main__.D object at 0x...>
     super(B, self).__init__()
     print("leave B")
    class C(A):
     def __init__(self):
     print("enter C")
     print(self) # this will print <__main__.D object at 0x...>
     super(C, self).__init__()
     print("leave C")
    class D(B, C):
     pass
    d = D()
    print("""这是D的MRO顺序:""",d.__class__.__mro__,"""super的本质如下:def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1]""")

    运行结果:

    enter B
    <__main__.D object at 0x10a833390>
    enter C
    <__main__.D object at 0x10a833390>
    enter A
    <__main__.D object at 0x10a833390>
    leave A
    leave C
    leave B
    这是D的MRO顺序: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) super的本质如下:def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1]

    没有昵称

    noe***[email protected]

    参考地址

    6年前 (2020年04月18日)
  4. #0

    WillYW

    187***[email protected]

    63

    Python3 中继承遵循广度优先原则:

    class A:
     def __init__(self):
     print("Enter A")
     print(self)
     print("Leave A")
    class B(A):
     def __init__(self):
     print("Enter B")
     print(self)
     super(B, self).__init__()
     print("Leave B")
    class C(A):
     def __init__(self):
     print("Enter C")
     print(self)
     super(C, self).__init__()
     print("Leave C")
    class D(B, C):
     def __init__(self):
     print("Enter D")
     print(self)
     super(D, self).__init__()
     print("Leave D")
    d = D()

    运行结果:

    Enter D
    <__main__.D object at 0x7fdb02618490>
    Enter B
    <__main__.D object at 0x7fdb02618490>
    Enter C
    <__main__.D object at 0x7fdb02618490>
    Enter A
    <__main__.D object at 0x7fdb02618490>
    Leave A
    Leave C
    Leave B
    Leave D

    1.创建 D 类的对象 d 时,自动调用 D 类的初始化方法 __init()__,此时的 self 指向 D 类创建的实例对象 d;

    2.调用原则:D->B->C->A

    3.在调用到 B 时,首先输出 "Enter B",但是运行到父类 A 的初始化方法时不立即调用,反而时转向广度优先级高的 C 类,因为 A 类对于 B 类来说是深度遍历。

    WillYW

    187***[email protected]

    6年前 (2020年07月23日)

点我分享笔记

  • 昵称 (必填)
  • 邮箱 (必填)
  • 引用地址

AltStyle によって変換されたページ (->オリジナル) /