【问题标题】:Cooperative multiple inheritance issue协同多重继承问题
【发布时间】:2013-04-24 16:26:51
【问题描述】:

这是对this question 的扩展,并提出了一个问题,您,我的 StackOverflowers 伙伴,希望能够帮助我。从引用的问题中,考虑最终的代码示例:

class A(object):
    def __init__(self):
        print "entering A"
        print "leaving A"

class B(object):
    def __init__(self):
        print "entering B"
        super(B, self).__init__()
        print "leaving B"

class C(A,B):
    def __init__(self):
        print "entering c"
        super(C, self).__init__()
        print "leaving c"

正如海报所指出的,在初始化 C 时,B 的 __init__ 永远不会被调用。考虑到Raymond Hettinger's postclass A 的代码应该修改为也调用super().__init__()

class A(object):
    def __init__(self):
        print "entering A"
        super(A, self).__init__()
        print "leaving A"

到目前为止,我们都很好。但是,如果我们类的 __init__ 函数接受参数怎么办?让我们假设所有__init__ 函数都接受一个参数,为了保持一致性,我们简单地称它为foo,现在的代码是:

class A(object):
    def __init__(self, foo):
        print "entering A"
        super(A, self).__init__(foo)
        print "leaving A"

class B(object):
    def __init__(self, foo):
        print "entering B"
        super(B, self).__init__(foo)
        print "leaving B"

class C(A,B):
    def __init__(self, foo):
        print "entering c"
        super(C, self).__init__(foo)
        print "leaving c"

在这里我们遇到了障碍。在初始化任何类 A、B 或 C 时,我们最终会使用单个参数 foo 调用 object.__init__,而 TypeError: object.__init__() takes no parameters 会出错。但是,删除super().__init__ 函数之一将意味着在多重继承的情况下类不再协作。

毕竟,我的问题是如何解决这个问题?除了没有参数传递给 __init__ 函数的情况外,似乎在任何情况下都破坏了多重继承。

更新:

cmets 中的 Rob 建议剥离关键字参数(在 Raymond H 的帖子中引用)。在您更改代码之前,这实际上在多重继承的情况下非常有效。如果您的函数之一不再使用关键字参数之一,并且在不修改调用函数的情况下停止剥离它,您仍然会收到上面提到的 TypeError。因此,对于大型项目来说,这似乎是一个脆弱的解决方案。

【问题讨论】:

  • FWIW,“好的设计要求此方法在每种情况下都具有相同的调用签名” -- docs.python.org/2/library/functions.html#super
  • 另外,请参阅rhettinger.wordpress.com/2011/05/26/super-considered-super,尤其是有关为.__init__() 使用关键字参数的部分。
  • @Robᵩ 理解,但我无法控制 object.__init__ 的签名,并且 __init__ 类函数接受参数是非常正常的。似乎 object.__init__ 应该被定义为 __init__(*args, **kwargs) 然后忽略传入的任何内容。
  • @Robᵩ 我已经引用了 Raymond Hettinger 的帖子。删除关键字可能会有所帮助...我将不得不考虑更多。

标签: python inheritance multiple-inheritance


【解决方案1】:

我的回答可能有点不对劲。我一直在寻找代码来解决我的特定问题。但是在搜索了几个小时后,我找不到很好的例子。所以我写了这个小测试代码。我认为这绝对是合作多重继承的例子。我真的认为有人可能会觉得它很有用。 所以我们开始吧!

基本上,我有一个相当大的班级,我想进一步拆分,但由于我的特殊情况,它必须是同一个班级。此外,我所有的子类都有自己的 init,可以这么说,我想在 base init 之后执行它们。

测试代码

"""
Testing MRO Functionality of python 2.6 (2.7)
"""


class Base(object):
    def __init__(self, base_arg, **kwargs):
        print "Base Init with arg: ", str(base_arg)
        super(Base, self).__init__()

    def base_method1(self):
        print "Base Method 1"

    def base_method2(self):
        print "Base Method 2"


class ChildA(Base):
    def __init__(self, child_a_arg, **kwargs):
        super(ChildA, self).__init__(**kwargs)
        print "Child A init with arg: ", str(child_a_arg)

    def base_method1(self):
        print "Base Method 1 overwritten by Child A"


class ChildB(Base):
    def __init__(self, child_b_arg, **kwargs):
        super(ChildB, self).__init__(**kwargs)
        print "Child B init with arg: ", str(child_b_arg)

    def base_method2(self):
        print "Base Method 2 overwritten by Child B"


class ChildC(Base):
    def __init__(self, child_c_arg, **kwargs):
        super(ChildC, self).__init__(**kwargs)
        print "Child C init with arg: ", str(child_c_arg)

    def base_method2(self):
        print "Base Method 2 overwritten by Child C"


class Composite(ChildA, ChildB, ChildC):
    def __init__(self):
        super(Composite, self).__init__(base_arg=1, child_a_arg=2, child_b_arg=3, child_c_arg=4)
        print "Congrats! Init is complete!"


if __name__ == '__main__':
    print "MRO: ", str(Composite.__mro__), "\n"
    print "*** Init Test ***"
    test = Composite()
    print "*** Base Method 1 Test ***"
    test.base_method1()
    print "*** Base Method 2 Test ***"
    test.base_method2()

输出

MRO:  (<class '__main__.Composite'>, 
       <class '__main__.ChildA'>, 
       <class '__main__.ChildB'>, 
       <class '__main__.ChildC'>, 
       <class '__main__.Base'>, 
       <type 'object'>)

*** Init Test ***
Base Init with arg:  1
Child C init with arg:  4
Child B init with arg:  3
Child A init with arg:  2
Congrats! Init is complete!
*** Base Method 1 Test ***
Base Method 1 overwritten by Child A
*** Base Method 2 Test ***
Base Method 2 overwritten by Child B

【讨论】:

    【解决方案2】:

    诚然,这个解决方案可能不是最 Pythonic 或最理想的,但像这样为对象创建一个包装类允许您在继承中围绕每个 __init__ 传递参数:

    class Object(object):
        def __init__(self,*args,**kwargs):
            super(Object,self).__init__()
    
    class A(Object):
        def __init__(self,*args,**kwargs):
            super(A,self).__init__(*args,**kwargs)
    
    class B(Object):
        def __init__(self,*args,**kwargs):
            super(B,self).__init__(*args,**kwargs)
    
    class C(A,B):
        def __init__(self,*args,**kwargs):
            super(C,self).__init__(*args,**kwargs)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-08
      • 2021-05-08
      • 1970-01-01
      • 1970-01-01
      • 2020-07-24
      • 1970-01-01
      相关资源
      最近更新 更多