python - 在 Python 中使用 super(),我不明白最后一次调用 __init__

标签 python python-3.x multiple-inheritance

我有如下三个类:

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)

我实例化了一个 ReportingPage 对象。为此,Python 向上爬取 MRO:

  1. 首先调用 Page 对象,因为它在 ReportingPage 的继承列表中排在第一位,它调用自己的 __init__ 方法。

  2. 然后它对Report 做同样的事情。

有两点我不明白:

  1. 为什么我必须将参数传递给 Page 中的 super.__init__,当 Page只是调用 __init__ 它继承自 object

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

最佳答案

super() 查看当前实例 的 MRO。当前 class 仅继承自 object 在这里并不重要。

ReportingPage 的 MRO 将 Report 放在 Pageobject 之间:

>>> ReportingPage.__mro__
(<class '__main__.ReportingPage'>, <class '__main__.Page'>, <class '__main__.Report'>, <class 'object'>)

所以当你在 Page.__init__() 中调用 super() 时,MRO 中的下一个类是 Report,你结束向上调用 Report.__init__ 方法。

你需要让你的类(class)更加合作;你可以使用关键字参数和一个包罗万象的 **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)

每个方法将此处剩余的关键字参数传递给 MRO 中的下一个 __init__,最后您将有一个空字典传递给 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>

只有 title 保留下来,Report.__init__() 消耗它,所以一个空的 kwargs 字典被传递给 object.__init__ ()

您可能对 Raymond Hettinger's super considered super 感兴趣,包括他的 PyCon 2015 presentation .

关于python - 在 Python 中使用 super(),我不明白最后一次调用 __init__,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50953637/

相关文章:

python - 查找过程中如何涉及 `__getattribute__` 方法?

php - 使用 PhpDoc 记录 PHP 多重继承

c++ - 了解多继承的vptr?

python - 带有 docker : __init__() got an unexpected keyword argument 'column' 的 Jupyter

python - 替换 DataFrame 中时间戳的日期部分

python - 设置函数属性的装饰器

c++ - 消除多重继承中的类成员歧义

python - python 3 和 tkinter 中的单选按钮

python-3.x - 这是 pickle 实例方法的正确方法吗?如果是,为什么不在 Python 3 中?

python - 基于用户定义的类创建动态 ABC 类