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

时间:2013-10-09 18:46:19

标签: python inheritance python-requests super

我正在寻找requests模块的来源,并注意到this code:

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()的理解表明这个电话根本不会做任何事情。我发现quite有一些questions关于superclass calling,但所有这些都来自其他类的子类,而不是object本身。 python docs也没有提到这种结构。

我觉得这可能只是一个错误,如果你git blamecommit that introduced that line提交了文件,你会发现在作者身份时,Response是一个BaseResponse的子类。该行只是一个类重构的延续,还是这个super()调用做了什么呢?

3 个答案:

答案 0 :(得分:4)

如果 Response 成为多重继承树的一部分,则此代码实际上可能会执行某些操作。 &#34; MRO&#34;中的下一课程列表可能是 object 之外的其他内容!在这种情况下,对 super 的调用可能非常必要

例如,

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

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

我认为一个问题是名称​​ super 会导致混淆。它不像Smalltalk的 super 变量那样,除非你只使用单继承,并且它不会返回&#34;超类&#34;宾语。相反,它正在做的是找出&#34; next&#34;根据MRO命令使用的类。

关于这个主题的经典文章是: Python's Super Considered SuperPython's Super Considered Harmful

答案 1 :(得分:2)

Corley Brigman's comment所述,这是不必要的,但无害。

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

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

后来在重构中,由于不必要的复杂性,这再次被拉出来。现实情况是,想要定义专门的Response对象的人可以简单地将Response子类化,而不是让ABC不做任何事情。这使得主线用例(vanilla Requests)在代码中更加清晰,并且几乎没有任何实用程序。

Response课程被拔出时,这一行被忽略了,但由于它没有引起任何问题,因此从未需要删除它。

答案 2 :(得分:0)

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