为什么继承'object' python 类会在其 __init__ 方法中调用'super'?



我在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该文件到引入该行的提交,你会看到在作者身份时,ResponseBaseResponse的一个子类。该行只是类重构的保留,还是这个 super(( 调用有任何作用?

如果响应成为多重继承树的一部分,此代码实际上可能会执行某些操作。 "MRO"列表中的下一个类可能是对象以外的其他类! 在这种情况下,调用超级可能是非常必要的

例如

class NewerClass(A, Response):
    def __init__(self):
        ... do stuff ...
        super(NewerClass, self).__init__()

根据该类定义,如果不知道 A 的层次结构是什么,则无法确定super(Response, self).__init__()调用的下一个类是什么。 它可能是对象,也可能是 A 的基类。

我认为一个问题是这个名字超级会引起混淆。 它不像 Smalltalk 的超级变量,除非你只使用单个继承,并且它不返回"超类"对象。 相反,它正在做的是根据 MRO 顺序找出要使用的"下一个"类。

关于该主题的经典文章是:Python的Super被认为是超级的,Python的Super被认为是有害的。

正如Corley Brigman的评论中提到的,这是不必要的,但无害。

对于一些背景,BaseResponse类是在 Kenneth 冲刺请求 1.0 期间添加的。1.0 代码更改引入了传输适配器,这使得为某些 HTTP 端点(或非 HTTP 端点(定义特定行为成为可能。传输适配器接口的一个重要部分是 HTTPAdapter.build_response() 方法,该方法从HTTPAdapter.send()获取返回的原始响应,并从中生成请求Response对象。

很明显,Kenneth 看到了为 Response 提供某种形式的抽象基类的潜在效用,这将允许传输适配器以非常不同的行为返回 Response 标准 HTTP Response 对象。出于这个原因,重构为具有子类中大部分逻辑的 ABC 似乎是有意义的。

在重构的后期,这再次被拉出不必要的复杂性。现实情况是,想要定义特殊Response对象的人可以简单地子类化Response,而不是拥有一个什么都不做的ABC。这使得主线用例(香草请求(在代码中更加干净,并且几乎没有任何实用程序。

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'>)

最新更新