Python内置函数(30)——super
英文文檔:
super([type[,?object-or-type]])
Return a proxy object that delegates method calls to a parent or sibling class of?type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by?getattr()?except that the?type?itself is skipped.
The?__mro__?attribute of the?type?lists the method resolution search order used by both?getattr()?and?super(). The attribute is dynamic and can change whenever the inheritance hierarchy is updated.
If the second argument is omitted, the super object returned is unbound. If the second argument is an object,?isinstance(obj,?type)?must be true. If the second argument is a type,?issubclass(type2,?type)?must be true (this is useful for classmethods).
There are two typical use cases for?super. In a class hierarchy with single inheritance,?super?can be used to refer to parent classes without naming them explicitly, thus making the code more maintainable. This use closely parallels the use of?super?in other programming languages.
The second use case is to support cooperative multiple inheritance in a dynamic execution environment. This use case is unique to Python and is not found in statically compiled languages or languages that only support single inheritance. This makes it possible to implement “diamond diagrams” where multiple base classes implement the same method. Good design dictates that this method have the same calling signature in every case (because the order of calls is determined at runtime, because that order adapts to changes in the class hierarchy, and because that order can include sibling classes that are unknown prior to runtime).
Note that?super()?is implemented as part of the binding process for explicit dotted attribute lookups such as?super().__getitem__(name). It does so by implementing its own?__getattribute__()?method for searching classes in a predictable order that supports cooperative multiple inheritance. Accordingly,?super()?is undefined for implicit lookups using statements or operators such as?super()[name].
Also note that, aside from the zero argument form,?super()?is not limited to use inside methods. The two argument form specifies the arguments exactly and makes the appropriate references. The zero argument form only works inside a class definition, as the compiler fills in the necessary details to correctly retrieve the class being defined, as well as accessing the current instance for ordinary methods.
? 根據(jù)傳入的參數(shù)生成一個(gè)新的子類和父類關(guān)系的代理對(duì)象
說明:
1. super函數(shù)返回的是一個(gè)代理對(duì)象,通過此對(duì)象可以調(diào)用所在類的父類或者兄弟類的方法,而不顯示的指定父類或者兄弟類的類名。
2. 為什么要有super?
最早之前,在子類(B)中調(diào)用父類(A)的方法采用的方式如下:?
#定義父類A >>> class A(object):def __init__(self):print('A.__init__')#實(shí)例化A >>> a = A() A.__init__# 定義子類B,繼承A,在B的__init__ 方法中調(diào)用A的__init__方法 >>> class B(A): def __init__(self):print('B.__init__')A.__init__(self)#實(shí)例化B >>> b = B() B.__init__ A.__init__假設(shè)現(xiàn)在要更改新定義一個(gè)類(A1),并更改繼承關(guān)系(B->A改成B->A1),則需要所有類中做如下修改:
#定義新的父類A1 >>> class A1(object):def __init__(self):print('A1.__init__')#更改繼承關(guān)系B->A改成B->A1 >>> class B(A1):def __init__(self):print('B.__init__')A1.__init__(self)#能正確調(diào)用新的父類A1的__init__方法 >>> b = B() B.__init__ A1.__init__#假設(shè)忘了修改A.__init__(self) >>> class B(A1):def __init__(self):print('B.__init__')A.__init__(self)#則還是調(diào)用了A的__init__方法 >>> b = B() B.__init__ A.__init__引入super之后,不需要顯示指定父類的類名,增強(qiáng)了程序的可維護(hù)性:
#B->A 改用super方式調(diào)用父類方法 >>> class B(A):def __init__(self):print('B.__init__')super().__init__()#能正確調(diào)用父類方法 >>> b = B() B.__init__ A.__init__#更改繼承關(guān)系B->A改成B->A1,調(diào)用父類方法方式不用修改 >>> class B(A1):def __init__(self):print('B.__init__')super().__init__()#也能正確調(diào)用父類方法 >>> b = B() B.__init__ A1.__init__3. 不帶任何參數(shù)的super等效于super(類名,self),此種情況多用于單繼承關(guān)系的子類中。
#super不帶參數(shù) >>> class B(A1):def __init__(self):print('B.__init__')super().__init__()#能正確調(diào)用父類方法 >>> b = B() B.__init__ A1.__init__#super帶兩個(gè)參數(shù)(類名,self) >>> class B(A1):def __init__(self):print('B.__init__')super(B,self).__init__()#也能正確調(diào)用父類方法 >>> b = B() B.__init__ A1.__init__4. 如果第2個(gè)參數(shù)不傳入,則表示代理對(duì)象不綁定繼承關(guān)系。
#super第2個(gè)參數(shù)不傳入,生成代理對(duì)象不綁定繼承關(guān)系 >>> class B(A1):def __init__(self):print('B.__init__')super(B).__init__()#super(B).__init__()方法執(zhí)行時(shí)不會(huì)調(diào)用父類方法 >>> b = B() B.__init__5. 如果第2個(gè)參數(shù)是一個(gè)對(duì)象,則對(duì)象必須是第1個(gè)參數(shù)指定類型的實(shí)例,此種關(guān)系多用于多層繼承關(guān)系的子類中。
#定義父類A >>> class A(object):def __init__(self):print('A.__init__')#定義子類B,繼承A,__init__中調(diào)用父類的__init__方法 >>> class B(A):def __init__(self):print('B.__init__')super().__init__()#定義子類C,繼承B,__init__中調(diào)用父類的__init__方法 >>> class C(B):def __init__(self):print('C.__init__')super().__init__()#實(shí)例化C時(shí),執(zhí)行C的__init__方法,調(diào)用直接父類B的__init__方法,又進(jìn)一步調(diào)用間接父類A的__init__方法 >>> c = C() C.__init__ B.__init__ A.__init__#重新定義子類C,繼承關(guān)系不變,調(diào)用父類方法__init__時(shí)改用super(B,self) >>> class C(B):def __init__(self):print('C.__init__')super(B,self).__init__()#實(shí)例化C時(shí),執(zhí)行C的__init__方法,super(B,self)代理找到B的父類A,將self轉(zhuǎn)換成B的實(shí)例,直接調(diào)用了A的__init__方法,跳過了調(diào)用B的__init__方法 >>> c = C() C.__init__ A.__init__#定義一個(gè)新類D >>> class D(object):def __init__(self):print('D.__init__')#重新定義C,繼承關(guān)系不變,調(diào)用父類方法__init__時(shí)改用super(D,self) >>> class C(B):def __init__(self):print('C.__init__')super(D,self).__init__()#實(shí)例化C時(shí),執(zhí)行C的__init__方法,super(D,self)代理找到D的父類object,將self轉(zhuǎn)換成D的實(shí)例,因?yàn)镈和C無繼承關(guān)系,self 無法轉(zhuǎn)換成D的實(shí)例所以報(bào)錯(cuò) >>> c= C() C.__init__ Traceback (most recent call last):File "<pyshell#14>", line 1, in <module>c= C()File "<pyshell#13>", line 4, in __init__super(D,self).__init__() TypeError: super(type, obj): obj must be an instance or subtype of type6. 如果第2個(gè)參數(shù)時(shí)一個(gè)類型,則類型必須是第1個(gè)參數(shù)指定類型的子類,此種關(guān)系多用于多層繼承關(guān)系的子類中,適用于類方法。
#定義父類A,并定義有一個(gè)類方法sayHello >>> class A(object):@classmethoddef sayHello(cls):print('A.sayHello')# 定義子類B,繼承A,重寫類方法sayHello,在其中調(diào)用父類的sayHello方法 >>> class B(A):@classmethoddef sayHello(cls):print('B.sayHello')super().sayHello()# 定義子類C,繼承B,重寫類方法sayHello,在其中調(diào)用父類的sayHello方法 >>> class C(B):@classmethoddef sayHello(cls):print('C.sayHello')super().sayHello()#調(diào)用C的類方法sayHello,其調(diào)用C的直接父類B的類方法sayHello,調(diào)用時(shí)B的sayHello方法又調(diào)用B的直接父類A的類方法sayHello >>> C.sayHello() C.sayHello B.sayHello A.sayHello#重新定義類C,繼承關(guān)系不變,使用super(C,C)的方式調(diào)用父類方法 >>> class C(B):@classmethoddef sayHello(cls):print('C.sayHello')super(C,C).sayHello()#調(diào)用C的類方法sayHello,super(C,C)代理對(duì)象,找到C的直接父類B,然后調(diào)用C的直接父類B的類方法sayHello,調(diào)用時(shí)B的sayHello方法又調(diào)用B的直接父類A的類方法sayHello >>> C.sayHello() C.sayHello B.sayHello A.sayHello#重新定義類C,繼承關(guān)系不變,使用super(B,C)的方式調(diào)用父類方法 >>> class C(B):@classmethoddef sayHello(cls):print('C.sayHello')super(B,C).sayHello()#調(diào)用C的類方法sayHello,super(B,C)代理對(duì)象,找到B的直接父類A,然后調(diào)用B的直接父類A的類方法sayHello,中間不會(huì)調(diào)用B的sayHello方法 >>> C.sayHello() C.sayHello A.sayHello#定義一個(gè)新類D,和A、B、C無繼承關(guān)系 >>> class D(object):@classmethoddef sayHello(cls):print('D.sayHello')#重新定義類C,繼承關(guān)系不變,使用super(D,C)的方式調(diào)用父類方法 >>> class C(B):@classmethoddef sayHello(cls):print('C.sayHello')super(D,C).sayHello()#調(diào)用C的類方法sayHello,super(D,C)代理對(duì)象,找到B的直接父類object,然后將C轉(zhuǎn)換成D類,轉(zhuǎn)換失敗調(diào)用出錯(cuò) >>> C.sayHello() C.sayHello Traceback (most recent call last):File "<pyshell#81>", line 1, in <module>C.sayHello()File "<pyshell#80>", line 5, in sayHellosuper(D,C).sayHello() TypeError: super(type, obj): obj must be an instance or subtype of type?
轉(zhuǎn)載于:https://www.cnblogs.com/lincappu/p/8144873.html
總結(jié)
以上是生活随笔為你收集整理的Python内置函数(30)——super的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国电信线CTF线下选拨writeup
- 下一篇: hihoCoder #1639 图书馆