【问题标题】:Multiple inheritance: only 1 parent init'd [duplicate]多重继承:只有1个父级初始化[重复]
【发布时间】:2013-12-01 14:45:52
【问题描述】:

我不明白为什么在下面的代码中只初始化了一个父构造函数:

class Base(object):
    def __init__(self):
        print "Base::Base():"


class BaseWArgs(object):
    def __init__(self, arg):
        print "BaseWArgs::BaseWArgs(%s):" % arg


class Composite(Base, BaseWArgs):
    def __init__(self):
        super(Composite,self).__init__()

在这种情况下,只有 Base.init() 被调用。如果我切换继承参数的顺序,只有whatever-stands-first类被初始化:

class Composite(BaseWArgs, Base):
    def __init__(self):
        super(Composite,self).__init__('myArg')

如何通过一个电话初始化两个父母?这不应该是super()的责任吗?

编辑 我认为我的用例是多重继承的一个特例。我想使用 defaultdict 作为基本类型创建一个项目,但从第三种类型继承一些额外的功能。

from collections import defaultdict

class Base(object):
    def __init__(self):
        print "Base::Base():"
        super(Base,self).__init__()
        self.val = 'hello world'

class Item(defaultdict, Base):
    def __init__(self):
        super(Item,self).__init__(int)

>>> Item()
defaultdict(<type 'int'>, {})

>>> Item().val
Traceback (most recent call last):
  File "<pyshell#77>", line 1, in <module>
    Item().val
AttributeError: 'Item' object has no attribute 'val'

Base::Base() 在哪里迷路了?为什么Base没有初始化?

【问题讨论】:

  • 在任何人开始链接到“超级有害”的东西之前:Python’s super() considered super!
  • 您必须使用两次supersuper 只是遍历__mro__(方法解析顺序)以找到要调用的方法,但它总是找到一个方法,即第一个方法层次结构。
  • @Bakuriu 使用super() 两次调用相同的Base.__init__() 两次。
  • 你应该阅读新的python类和继承,这是因为python不会搜索它首先靠近的所有父母。
  • @PavloDyban 阅读我的评论。我有没有说过两次使用相同的参数调用super?我显然打算调用super两次,使用不同的参数来获得这两个方法。

标签: python python-2.7 initialization multiple-inheritance


【解决方案1】:

Base.__init__BaseWArgs.__init__ 都没有实现对 super().__init__ 的调用,所以显然只有 rmo 中的第一个会被调用。您必须让所有初始化程序都尊重协议才能工作。

另外,Base 在 mro 中排在第一位并且不接受任何参数,这仍然会失败。 “协作”超级调用要求您的方法签名兼容。下面的代码确实按预期委托调用:

class Base(object):
    def __init__(self):
        print "Base::Base():"
        super(Base, self).__init__()

class BaseWArgs(object):
    def __init__(self, arg):
        print "BaseWArgs::BaseWArgs(%s):" % arg
        super(BaseWArgs, self).__init__()


class Composite(BaseWArgs, Base):
    def __init__(self):
        super(Composite,self).__init__("foo")

c = Composite()

编辑:wrt/您的具体用例,似乎defaultdict 不会自己调用super,所以除非它是您的基类中的最后一个,否则调用链将停在那里(嗯,它 到此为止,但如果最后出现,那也不是问题)。

所以你的选择是要么让你自己的Base层次结构的初始化器与defaultdict的初始化器兼容,并将defaultdict作为最后一个基类,要么显式调用defaultdict的初始化器然后Base初始化器,即:

class Base(object):
    def __init__(self):
        print "Base__init__():"
        super(Base, self).__init__()

class Sub(Base):
    def __init__(self):
        print "Sub.__init__():"
        super(Sub, self).__init__()
        self.foo = "bar"


class MyClass(defaultdict, Sub):
    def __init__(self):
        defaultdict.__init__(self, int)
        Sub.__init__(self)

【讨论】:

  • 这解释了为什么在 defaultdict 和我自己的 Base 类之间切换位置解决了继承问题。那是因为defaultdict 没有继承自object 并且没有实现super().__init__()
  • @PavloDyban defaultdict 确实继承自 object,虽然不是直接
  • @PavloDyban : 对不起先生,但 defaultdict 确实继承自 object - 现在我不知道它是否调用 super
  • 那我又卡住了。
  • @PavloDyban:你的真实用例是什么?
猜你喜欢
  • 2020-07-30
  • 1970-01-01
  • 2019-10-07
  • 1970-01-01
  • 2019-08-03
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 1970-01-01
相关资源
最近更新 更多