在Python中使用super(),我不理解最后一次__init__调用

Dre*_*man 4 python multiple-inheritance python-3.x

我有三个课程如下:

class Page(object):
    def __init__(self, Obj_a, Obj_b):
        super().__init__(Obj_a, Obj_b)

class Report(object):
    def __init__(self, Obj_a, Obj_b):
        super().__init__()

class ReportingPage(Page,Report):
    def __init__(self, Obj_a, Obj_b):
        super().__init__(Obj_a, Obj_b)
Run Code Online (Sandbox Code Playgroud)

我实例化一个ReportingPage对象.要做到这一点,Python爬行MRO:

  1. Page首先调用该对象,因为它首先在继承列表中排序ReportingPage,然后调用它自己的__init__方法.

  2. 然后它也是这样做的Report.

我不明白的两件事:

  1. 为什么我必须将参数传递给super.__init__in Page,什么Page时候才会调用__init__它继承的内容,object.

  2. 为什么我不必为此做同样的事情Report.

Mar*_*ers 6

super()查看当前实例的MRO .这里没有关系,当前只继承自object.

的MRO ReportingPage看跌期权Report之间Pageobject:

>>> ReportingPage.__mro__
(<class '__main__.ReportingPage'>, <class '__main__.Page'>, <class '__main__.Report'>, <class 'object'>)
Run Code Online (Sandbox Code Playgroud)

所以,当你打电话super()Page.__init__(),在MRO下一类是Report,你最终调用的Report.__init__方法.

你需要让你的课程更合作; 你可以使用关键字参数和一个catch-all **kwargs参数来做到这一点:

class Page(object):
    def __init__(self, pagenum, **kwargs):
        self.pagenum = pagenum
        super().__init__(**kwargs)

class Report(object):
    def __init__(self, title, **kwargs):
        self.title = title
        super().__init__(**kwargs)

class ReportingPage(Page, Report):
    def __init__(self, footer=None, **kwargs):
        self.footer = footer
        super().__init__(**kwargs)
Run Code Online (Sandbox Code Playgroud)

每个方法都将此处的剩余关键字参数传递给__init__MRO中的下一个,最后您将有一个空字典传递给它object.__init__().如果print(kwargs)为每个__init__方法添加一个包装器,您可以看到kwargs随着较少的值传递给下一个调用而变小.

>>> def print_wrapper(name, f):
...     def wrapper(*args, **kwargs):
...         print(name, '->', kwargs)
...         return f(*args, **kwargs)
...     return wrapper
...
>>> for cls in ReportingPage.__mro__[:-1]:  # all except object
...     cls.__init__ = print_wrapper(cls.__name__, cls.__init__)
...
>>> ReportingPage(title='Watching Paint Dry II: The Second Coat', pagenum=42)
ReportingPage -> {'title': 'Watching Paint Dry II: The Second Coat', 'pagenum': 42}
Page -> {'title': 'Watching Paint Dry II: The Second Coat', 'pagenum': 42}
Report -> {'title': 'Watching Paint Dry II: The Second Coat'}
<__main__.ReportingPage object at 0x109e3c1d0>
Run Code Online (Sandbox Code Playgroud)

只有title保持,这Report.__init__()消耗,所以一个空的kwargs字典传递给object.__init__()

您可能对Raymond Hettinger的超级考虑超级感兴趣,包括他的PyCon 2015演示.