在 Python 中使用 super(),我不明白最后一个 __init__ 调用
Using super() in Python, I do not understand this last __init__ call
我有三个类如下:
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:
首先调用 Page
对象,因为它在 ReportingPage
的继承列表中排在第一位,它调用自己的 __init__
方法。
然后它对 Report
做同样的事情。
两件事我不明白:
为什么我 必须 将参数传递给 Page
中的 super.__init__
,而 Page
正要调用 __init__
它继承自 object
的内容。
为什么我不必为 Report
做同样的事情。
super()
查看当前实例的MRO。这里并不重要,当前的 class 仅继承自 object
.
ReportingPage
的 MRO 将 Report
置于 Page
和 object
之间:
>>> ReportingPage.__mro__
(<class '__main__.ReportingPage'>, <class '__main__.Page'>, <class '__main__.Report'>, <class 'object'>)
所以当你在 Page.__init__()
中调用 super()
时,MRO 中的下一个 class 是 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, including his PyCon 2015 presentation 感兴趣。
我有三个类如下:
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:
首先调用
Page
对象,因为它在ReportingPage
的继承列表中排在第一位,它调用自己的__init__
方法。然后它对
Report
做同样的事情。
两件事我不明白:
为什么我 必须 将参数传递给
Page
中的super.__init__
,而Page
正要调用__init__
它继承自object
的内容。为什么我不必为
Report
做同样的事情。
super()
查看当前实例的MRO。这里并不重要,当前的 class 仅继承自 object
.
ReportingPage
的 MRO 将 Report
置于 Page
和 object
之间:
>>> ReportingPage.__mro__
(<class '__main__.ReportingPage'>, <class '__main__.Page'>, <class '__main__.Report'>, <class 'object'>)
所以当你在 Page.__init__()
中调用 super()
时,MRO 中的下一个 class 是 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, including his PyCon 2015 presentation 感兴趣。