最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
当前位置: 首页 - 科技 - 知识百科 - 正文

深入解析Python编程中super关键字的用法

来源:懂视网 责编:小采 时间:2020-11-27 14:29:14
文档

深入解析Python编程中super关键字的用法

深入解析Python编程中super关键字的用法:官方文档中关于super的定义说的不是很多,大致意思是返回一个代理对象让你能够调用一些继承过来的方法,查找的机制遵循mro规则,最常用的情况如下面这个例子所示: class C(B): def method(self, arg): super(C, self).method(arg)
推荐度:
导读深入解析Python编程中super关键字的用法:官方文档中关于super的定义说的不是很多,大致意思是返回一个代理对象让你能够调用一些继承过来的方法,查找的机制遵循mro规则,最常用的情况如下面这个例子所示: class C(B): def method(self, arg): super(C, self).method(arg)

官方文档中关于super的定义说的不是很多,大致意思是返回一个代理对象让你能够调用一些继承过来的方法,查找的机制遵循mro规则,最常用的情况如下面这个例子所示:

class C(B):
 def method(self, arg):
 super(C, self).method(arg)

子类C重写了父类B中同名方法method,在重写的实现中通过super实例化的代理对象调用父类的同名方法。

super类的初始方法签名如下:

def __init__(self, type1, type2=None): # known special case of super.__init__
 """
 super(type, obj) -> bound super object; requires isinstance(obj, type)
 super(type) -> unbound super object
 super(type, type2) -> bound super object; requires issubclass(type2, type)
 Typical use to call a cooperative superclass method:

除去self外接受一个或者或者两个参数,如同注释声明的一样,接受两个参数时返回的是绑定的super实例,省略第二个参数的时候返回的是未绑定的super对象。

一般情况下当调用继承的类方法或者静态方法时,并不需要绑定具体的实例,这个时候使用super(type, type2).some_method就能达到目的,当然super(type, obj)在这种情况下也能够使用,super对象有自定义实现的getattribute方法也能够处理。不过,后者一般用来调用实例方法,这样在查找方法的时候能够传入相应的实例,从而得到绑定的实例方法:

class A(object):
 def __init__(self):
 pass

 @classmethod
 def klass_meth(cls):
 pass

 @staticmethod
 def static_meth():
 pass

 def test(self):
 pass

class B(A):
 pass

>>> b = B()
>>> super(B, b).test
>
>>> super(B, b).klass_meth
>
>>> super(B, b).static_meth

>>> super(B, B).test

>>> super(B, B).klass_meth
>
>>> super(B,B).satic_meth
>>> super(B,B).static_meth


初始化super对象的时候,传递的第二个参数其实是绑定的对象,第一个参感觉数可以粗暴地理解为标记查找的起点,比如上面例子中的情况:super(B, b).test就会在B.__mro__里面列出的除B本身的类中查找方法test,因为方法都是非数据描述符,在super对象的自定义getattribute里面实际上会转化成A.__dict['test'].__get__(b, B)。

super在很多地方都会用到,除了让程序不必hardcode指定类型让代码更加动态,还有其他一些具体必用的地方比如元类中使用super查找baseclass里面的new生成自定义的类型模板;在自定义getattribute的时候用来防止无限循环等等。

关于super建议读者将它与python的描述符一起来理解,因为super就实现了描述符的协议,是一个非数据描述符,能够帮助大家更好的理解super的使用和工作原理。

同时,有以下4个点值得大家注意:
1、单继承时super()和__init__()实现的功能是类似的

class Base(object):
 def __init__(self):
 print 'Base create'

class childA(Base):
 def __init__(self):
 print 'creat A ',
 Base.__init__(self)


class childB(Base):
 def __init__(self):
 print 'creat B ',
 super(childB, self).__init__()

base = Base()

a = childA()
b = childB()

输出结果:

Base create
creat A Base create
creat B Base create


使用super()继承时不用显式引用基类。

2、super()只能用于新式类中

把基类改为旧式类,即不继承任何基类

class Base():
 def __init__(self):
 print 'Base create'

执行时,在初始化b时就会报错:

 super(childB, self).__init__()
TypeError: must be type, not classobj

3、super不是父类,而是继承顺序的下一个类

在多重继承时会涉及继承顺序,super()相当于返回继承顺序的下一个类,而不是父类,类似于这样的功能:

def super(class_name, self):
 mro = self.__class__.mro()
 return mro[mro.index(class_name) + 1]

mro()用来获得类的继承顺序。

例如:

class Base(object):
 def __init__(self):
 print 'Base create'

class childA(Base):
 def __init__(self):
 print 'enter A '
 # Base.__init__(self)
 super(childA, self).__init__()
 print 'leave A'


class childB(Base):
 def __init__(self):
 print 'enter B '
 # Base.__init__(self)
 super(childB, self).__init__()
 print 'leave B'

class childC(childA, childB):
 pass

c = childC()
print c.__class__.__mro__

输入结果如下:

enter A 
enter B 
Base create
leave B
leave A
(, , , , )

supder和父类没有关联,因此执行顺序是A —> B—>—>Base

执行过程相当于:初始化childC()时,先会去调用childA的构造方法中的 super(childA, self).__init__(), super(childA, self)返回当前类的继承顺序中childA后的一个类childB;然后再执行childB().__init()__,这样顺序执行下去。

在多重继承里,如果把childA()中的 super(childA, self).__init__() 换成Base.__init__(self),在执行时,继承childA后就会直接跳到Base类里,而略过了childB:

enter A 
Base create
leave A
(, , , , )

从super()方法可以看出,super()的第一个参数可以是继承链中任意一个类的名字,

如果是本身就会依次继承下一个类;

如果是继承链里之前的类便会无限递归下去;

如果是继承链里之后的类便会忽略继承链汇总本身和传入类之间的类;

比如将childA()中的super改为:super(childC, self).__init__(),程序就会无限递归下去。

如:

 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
 File "C:/Users/Administrator/Desktop/crawler/learn.py", line 10, in __init__
 super(childC, self).__init__()
RuntimeError: maximum recursion depth exceeded while calling a Python object

4、super()可以避免重复调用

如果childA基础Base, childB继承childA和Base,如果childB需要调用Base的__init__()方法时,就会导致__init__()被执行两次:

class Base(object):
 def __init__(self):
 print 'Base create'

class childA(Base):
 def __init__(self):
 print 'enter A '
 Base.__init__(self)
 print 'leave A'


class childB(childA, Base):
 def __init__(self):
 childA.__init__(self)
 Base.__init__(self)

b = childB()
 Base的__init__()方法被执行了两次

enter A 
Base create
leave A
Base create
使用super()是可避免重复调用

class Base(object):
 def __init__(self):
 print 'Base create'

class childA(Base):
 def __init__(self):
 print 'enter A '
 super(childA, self).__init__()
 print 'leave A'


class childB(childA, Base):
 def __init__(self):
 super(childB, self).__init__()

b = childB()
print b.__class__.mro()

enter A 
Base create
leave A
[, , , ]

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文档

深入解析Python编程中super关键字的用法

深入解析Python编程中super关键字的用法:官方文档中关于super的定义说的不是很多,大致意思是返回一个代理对象让你能够调用一些继承过来的方法,查找的机制遵循mro规则,最常用的情况如下面这个例子所示: class C(B): def method(self, arg): super(C, self).method(arg)
推荐度:
标签: 使用 详解 解析
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top