![](/img/trans.png)
[英]Python: why should last class in MRO have zero parameter in its super's __init__ call or there would be runtime exception
[英]Why would a python class that inherits 'object' call 'super' in its __init__ method?
我正在尋找requests
模塊的源代碼 ,並注意到這段代碼:
class Response(object):
"""The :class:`Response <Response>` object, which contains a
server's response to an HTTP request.
"""
def __init__(self):
super(Response, self).__init__()
... more init method...
我對super()
理解表明這個調用根本不會做任何事情。 我發現了很多關於超類調用的 問題 ,但是所有工作都來自其他類的子類,而不是object
本身。 python文檔也沒有提到這種結構。
我想到這可能只是一個錯誤,如果你git blame
這個文件git blame
引入該行的提交 ,你會看到在作者時, Response
是BaseResponse
的子類。 該行只是一個類重構的延續,還是這個super()調用做了什么呢?
如果Response成為多重繼承樹的一部分,則此代碼實際上可能會執行某些操作。 “MRO”列表中的下一個類可能不是對象 ! 在這種情況下,對super的調用可能非常必要 。
例如,
class NewerClass(A, Response):
def __init__(self):
... do stuff ...
super(NewerClass, self).__init__()
從該類定義並且不知道A的層次結構是什么,您無法確定super(Response, self).__init__()
調用的下一個類。 它可能是對象 ,也可能是A的基類。
我認為一個問題是超級名稱引起混亂。 它不像Smalltalk的超級變量,除非你只使用單繼承,並且它不返回“超類”對象。 相反,它正在做的是根據MRO訂單確定要使用的“下一個”類。
關於這個主題的經典文章是: Python的Super Considered Super和Python的Super Considered Harmful 。
如Corley Brigman的評論所述 ,這是不必要但無害的。
對於某些背景,在Kenneth的Sprint期間,在Requests 1.0上添加了BaseResponse
類。 1.0代碼更改引入了傳輸適配器 ,這使得可以為某些HTTP端點(或實際上非HTTP端點 )定義特定行為。 傳輸適配器接口的一個重要部分是HTTPAdapter.build_response()
方法,它從HTTPAdapter.send()
獲取返回的原始響應,並HTTPAdapter.send()
構建一個Requests Response
對象。
很明顯,Kenneth看到了為Response
s提供某種形式的抽象基類的潛在效用,這將允許傳輸適配器將具有非常不同行為的Response
返回給標准HTTP Response
對象。 出於這個原因,使用子類中的大部分邏輯將重構轉換為ABC似乎是有意義的。
后來在重構中,這又被作為不必要的復雜性再次拉出來了。 現實情況是,人們希望確定專門的Response
對象可以簡單的子類Response
,而不是一個ABC,什么也不做多。 這使得主線用例(vanilla Requests)在代碼中更加清晰,並且幾乎沒有任何實用程序。
當BaseRequest
類被拔出時,這條線被忽略了,但由於它沒有引起任何問題,所以從來沒有需要刪除它。
darinbob是對的。 在談論單繼承時,它是不必要的,但是有了多重繼承,事情就不同了:
class WithSuper:
def __init__(self):
print('With super')
super().__init__()
class NoSuper:
def __init__(self):
print('No super')
class TestOne(WithSuper, NoSuper):
def __init__(self):
print('Test 1')
super().__init__()
class TestTwo(NoSuper, WithSuper):
def __init__(self):
print('Test 2')
super().__init__()
one = TestOne()
print(TestOne.__mro__)
print('\n' * 2)
two = TestTwo()
print(TestTwo.__mro__)
用python3運行上面的代碼,你會看到差異。
Test 1
With super
No super
(<class '__main__.TestOne'>, <class '__main__.WithSuper'>, <class '__main__.NoSuper'>, <class 'object'>)
Test 2
No super
(<class '__main__.TestTwo'>, <class '__main__.NoSuper'>, <class '__main__.WithSuper'>, <class 'object'>)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.