Python ---- super()使用

我们经常在类的继承当中使用super(), 来调用父类中的方法。例如下面:


1

2

3

4

5

6

7

8

9

10

11

12

13

class A:

    def func(self):

        print(‘OldBoy‘)

class B(A):

    def func(self):

        super().func()

        print(‘LuffyCity‘)

A().func()

B().func()

输出的结果为:

OldBoy
OldBoy
LuffyCity

A实例化的对象调用了func方法,打印输出了 Oldboy;

B实例化的对象调用了自己的func方法,先调用了父类的方法打印输出了 OldBoy ,再打印输出 LuffyCity 。

这样是Python3的写法,今天咱们也只讨论Python3中的super。

如果不使用super的话,想得到相同的输出截个,还可以这样写B的类:


1

2

3

4

class B(A):

    def func(self):

        A.func(self)

        print(‘LuffyCity‘)

这样能实现相同的效果,只不过传了一个self参数。那为什么还要使用super()呢?

那我看看有这样的一个继承关系的类(钻石继承):


1

2

3

4

5

6

7

  Base

  /  \

 /    \

A      B

 \    /

  \  /

   C

代码是这样的:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

class Base:

    def __init__(self):

        print(‘Base.__init__‘)

class A(Base):

    def __init__(self):

        Base.__init__(self)

        print(‘A.__init__‘)

class B(Base):

    def __init__(self):

        Base.__init__(self)

        print(‘B.__init__‘)

class C(A, B):

    def __init__(self):

        A.__init__(self)

        B.__init__(self)

        print(‘C.__init__‘)

C()

输出的结果是:

Base.__init__
A.__init__
Base.__init__
B.__init__
C.__init__

每个子类都调用父类的__init__方法,想把所有的初始化操作都做一遍,但是出现了一个问题,Base类的__init__方法被调用了两次,这是多余的操作,也是不合理的。

那我们改写成使用super()的写法:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

class Base:

    def __init__(self):

        print(‘Base.__init__‘)

class A(Base):

    def __init__(self):

        super().__init__()

        print(‘A.__init__‘)

class B(Base):

    def __init__(self):

        super().__init__()

        print(‘B.__init__‘)

class C(A, B):

    def __init__(self):

        super().__init__()

        print(‘C.__init__‘)

C()

输出的结果是:

Base.__init__
B.__init__
A.__init__
C.__init__ 

这样执行的结果就比较满意,是大多数人想要的结果。那为什么会是这样的结果呢?

那是因为我们每定义一个类的时候,Python都会创建一个MRO列表,用来管理类的继承顺序。


1

2

print(C.mro())

# [<class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘__main__.Base‘>, <class ‘object‘>]

Python通过这个列表从左到右,查找继承的信息。Python3中的类都是新式类,都有这个mro属性,能看出来是广度优先的查找原则。经典类就没有mro属性,但它的查找原则是深度优先。

那我回到super的问题上来,让我们先看看super的官方定义

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

返回一个代理对象,该对象将方法调用委托给类的父类或兄弟类。这对于访问类中已重写的继承方法非常有用。搜索顺序与getattr()使用的搜索顺序相同,只是类型本身被跳过。

类的__mro__属性列出了getattr()和super()使用的方法解析搜索顺序。属性是动态的,可以在继承层次结构更新时进行更改。

看到官方的解释就可以很清楚的明白,super是一个类,实例化之后得到的是一个代理的对象,而不是得到了父类,并且我们使用这个代理对象来调用父类或者兄弟类的方法。

那我们再看看super的使用方法:

super() -> same as super(__class__, <first argument>)super(type) -> unbound super objectsuper(type, obj) -> bound super object; requires isinstance(obj, type)super(type, type2) -> bound super object; requires issubclass(type2, type)

super至少需要一个参数,并且类型需要是类。

不传参数的会报错。只传一个参数的话是一个不绑定的对象,不绑定的话也就没什么用了。


1

2

print(super(C))

print(super())

输出结果:

RuntimeError: super(): no arguments
<super: <class ‘C‘>, NULL>

在定义类当中可以不写参数,Python会自动根据情况将两个参数传递给super。


1

2

3

4

5

6

7

8

class C(A, B):

    def __init__(self):

        print(super())

        super().__init__()

        print(‘C.__init__‘)

C()

输出结果:

<super: <class ‘C‘>, <C object>>
Base.__init__
B.__init__
A.__init__
C.__init__

所以我们在类中使用super的时候参数是可以省略的。

第三种用法, super(type, obj) 传递一个类和对象,得到的是一个绑定的super对象。这还需要obj是type的实例,可以不是直接的实例,是子类的实例也行。


1

2

3

= A()

print(super(A, a))

print(super(Base, a))

输出结果:

Base.__init__
A.__init__
<super: <class ‘A‘>, <A object>>
<super: <class ‘Base‘>, <A object>>

第三种用法, super(type, type2)传递两个类,得到的也是一个绑定的super对象。这需要type2是type的子类。


1

2

3

print(super(Base, A))

print(super(Base, B))

print(super(Base, C))

输出结果:

<super: <class ‘Base‘>, <A object>>
<super: <class ‘Base‘>, <B object>>
<super: <class ‘Base‘>, <C object>>

接下来我们就该说说查找顺序了,两个参数,是按照那个参数去计算MRO呢?

我们将C类中的super的参数填写上,并且实例化,看看输出的结果。


1

2

3

4

class C(A, B):

    def __init__(self):

        super(C, self).__init__()

        print(‘C.__init__‘)

输出结果:

Base.__init__
B.__init__
A.__init__
C.__init__

看结果和之前super没填参数的结果是一样的。

那我们将super的第一个参数改为A:


1

2

3

4

class C(A, B):

    def __init__(self):

        super(A, self).__init__()

        print(‘C.__init__‘)

输出结果:

Base.__init__
B.__init__
C.__init__

咦!?那A.__init__怎么跑丢了呢?多出来了B.__init__呢?

这是应为Python是按照第二个参数来计算MRO,这次的参数是self,也就是C的MRO。在这个顺序中跳过一个参数(A)找后面一个类(B),执行他的方法。

知道这个后,输出的结果就可以理解了。 super(A, self).__init__() 没有执行Base的方法,而是执行了B的方法。



那我们接下来说说 super(type, obj)  和 super(type, type2)的区别。

代码如下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

class Base:

    def func(self):

        return ‘from Base‘

class A(Base):

    def func(self):

        return ‘from A‘

class B(Base):

    def func(self):

        return ‘from B‘

class C(A, B):

    def func(self):

        return ‘from C‘

c_obj = C()

print(super(C, C))

print(super(C, c_obj))

输出结果:

<super: <class ‘C‘>, <C object>>
<super: <class ‘C‘>, <C object>>

两次的打印结果一模一样,verygood。那他们的方法是否是一样的呢?测试一下。


1

2

print(super(C, C).func is super(C, c_obj).func)

print(super(C, C).func == super(C, c_obj).func)

输出结果:

False
False

他俩的方法既不是指向同一个,值还不相等。是不是搞错了呢?再试试下面的看看。


1

2

3

4

5

6

c1 = super(C, C)

c2 = super(C, C)

print(c1 is c2)

print(c1 == c2)

print(c1.func is c2.func)

print(c1.func == c2.func)

输出结果:

False
False
True
True

c1和c2不是一个对象,但是他们的方法却是相同的。

那 super(C, C).func 和 super(C, c_obj).func 的确是不同的。那打印出来看看有什么区别:


1

2

print(super(C, C).func)

print(super(C, c_obj).func)

输出结果:

<function A.func at 0x0000000009F4D6A8>
<bound method A.func of <__main__.C object at 0x00000000022A94E0>>

super的第二个参数传递的是类,得到的是函数。

super的第二个参数传递的是对象,得到的是绑定方法。

函数和绑定方法的区别就不再赘述了,在这里想得到一样的结果,只需要给函数传递一个参数,而绑定方法则不需要传递额外的参数了。


1

2

print(super(C, C).func(c_obj))

print(super(C, c_obj).func())

输出结果:

from A
from A

那我现在总结一下:

  1. super()使用的时候需要传递两个参数,在类中可以省略不写,我们使用super()来找父类或者兄弟类的方法;
  2. super()是根据第二个参数来计算MRO,根据顺序查找第一个参数类后的方法。
  3. super()第二个参数是类,得到的方法是函数,使用时要传self参数。第二个参数是对象,得到的是绑定方法,不需要再传self参数。

给使用super()的一些建议:

  1. super()调用的方法要存在;
  2. 传递参数的时候,尽量使用*args 与**kwargs;
  3. 父类中的一些特性,比如【】、重写了__getattr__,super对象是不能使用的。
  4. super()第二个参数传的是类的时候,建议调用父类的类方法和静态方法。

原文地址:https://www.cnblogs.com/hanbowen/p/9886673.html

时间: 2024-11-09 03:16:48

Python ---- super()使用的相关文章

理解python super()类

首先我们通过网友在stackoverflow关于python super类的一个疑问来作为本篇的开始,问题大致是这样的: >>> class A(object): ... def __init__(self): ... print "A init" ... super(A,self).__init__() ... >>> >>> a = A() A init >>> class B(object): ... def

Python super() 函数

Python super() 函数  Python 内置函数 描述 super() 函数是用于调用父类(超类)的一个方法. super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO).重复调用(钻石继承)等种种问题. MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表. 语法 以下是 super() 方法的语法: super(type[, object-or-type]) 参数 type -- 类. obj

python super()

一.问题的发现与提出 在Python类的方法(method)中,要调用父类的某个方法,在Python 2.2以前,通常的写法如代码段1: 代码段1: class A: def __init__(self): print "enter A" print "leave A" class B(A): def __init__(self): print "enter B" A.__init__(self) print "leave B"

Python super初始化理解过程

Python中子类调用父类的方法有两种方法能够实现:调用父类构造方法,或者使用super函数(两者不要混用). 使用“super”时经常会出现代码“super(FooChild,self).__init__(xxx,xxx)”.那super().__init__()到底要怎么用呢? 为了方便理解,我写了如下例子验证用法: #-*- coding:utf-8 -*-class A(object): def __init__(self,xing,gender): #!#1 self.namea="a

python super()使用详解

1.super的作用调用父类方法2.单继承使用示例 #coding:utf-8 #单继承 class A(object): def __init__(self): self.n=2 def add(self,m): self.n+=m class B(A): def __init__(self): self.n=3 def add(self,m): super(B,self).add(m) self.n+=3 b=B() b.add(3) print b.n 运行结果: super(B,self

Python super继承详解

MRO(Method resolution order)是python用来解析方法调用顺序的,mro中记录了一个类的所有基类的类类型序列,super不是简单地调用基类的方法,而是按照MRO中的顺序来调用类的方法.使用super()时,应该在所有类中使用,否则就可能发生有的类构造函数没有调用的情况.#!/usr/bin/python# -*- coding: utf-8 -*-class A(object): def __init__(self): print 'A __init__' super

转载:python super()及相关引申

super()是Python类的方法(method),用来调用父类,superclass 即 超类(父类) 详细请看http://www.cnblogs.com/lovemo1314/archive/2011/05/03/2035005.html 用 [类名.mro()] 来查看 该类的mro的记录 关于Python 多重继承mro 详细请看:http://blog.sina.com.cn/s/blog_45ac0d0a01018488.html 关于深度优先和广度优先请看: http://ww

(转)Python: super 没那么简单

原文:https://mozillazg.com/2016/12/python-super-is-not-as-simple-as-you-thought.html python 约定? 单继承? 多继承? super 是个类? 多继承中 super 的工作方式? 参考资料? 说到 super, 大家可能觉得很简单呀,不就是用来调用父类方法的嘛.如果真的这么简单的话也就不会有这篇文章了,且听我细细道来.?? 约定 在开始之前我们来约定一下本文所使用的 Python 版本.默认用的是 Python

python super研究

# encoding=utf-8 class A(object): def __init__(self): print "初始化a" def run(self): print "运行a" class B(A): def __init__(self): print '开始初始化b' super(B, self).__init__() print '结束初始化b' def run(self): print "开始运行b" super(B, self)