簡體   English   中英

為什么繼承'object'的python類會在__init__方法中調用'super'?

[英]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 引入該行提交 ,你會看到在作者時, ResponseBaseResponse的子類。 該行只是一個類重構的延續,還是這個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 SuperPython的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM