7

我在模块的源代码上四处寻找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将该文件提交给引入该行的提交,您将看到在作者身份时,Response它是BaseResponse. 这条线只是类重构的保留,还是这个 super() 调用有什么作用?

4

3 回答 3

4

如果Response成为多重继承树的一部分,这段代码实际上可能会做一些事情。“MRO”列表中的下一个类可能不是object!在这种情况下,调用super可能是非常必要的。

例如,

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

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

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

有关该主题的经典文章有: Python 的 Super Considered SuperPython 的 Super Considered Harmful

于 2014-08-05T01:44:04.063 回答
2

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

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

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

后来在重构中,这又因为不必要的复杂性而被取消了。现实情况是,想要定义特殊Response对象的人可以简单地继承子类Response,而不是拥有一个什么都不做的 ABC。这使得代码中的主线用例(vanilla Requests)更加清晰,并且几乎没有带走任何实用程序。

BaseRequest班级被撤出时,这条线被忽略了,但由于它没有引起任何问题,所以从来不需要删除它。

于 2013-10-10T08:16:50.123 回答
0

达林博是对的。当谈到单继承时,它是不必要的,但是对于多继承,事情就不同了:

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'>)
于 2018-07-18T11:15:29.837 回答