【问题标题】:Inheritance in Python Such That All Base Functions Are CalledPython 中的继承,即调用所有基本函数
【发布时间】:2010-12-24 00:13:53
【问题描述】:

基本上,我想要的是这样做:

class B:
    def fn(self):
        print 'B'

class A:
    def fn(self):
        print 'A'

@extendInherit
class C(A,B):
    pass

c=C()
c.fn()

然后输出是

A
B

我将如何实现 extendInherit 装饰器?

【问题讨论】:

    标签: python inheritance decorator multiple-inheritance


    【解决方案1】:

    这不是装饰师的工作。你想彻底改变一个类的正常行为,所以这实际上是一个元类的工作。

    import types
    
    class CallAll(type):
        """ MetaClass that adds methods to call all superclass implementations """
        def __new__(meta, clsname, bases, attrs):
            ## collect a list of functions defined on superclasses
            funcs = {}
            for base in bases:
                for name, val in vars(base).iteritems():
                    if type(val) is types.FunctionType:
                        if name in funcs:
                            funcs[name].append( val )
                        else:
                            funcs[name] = [val]
    
            ## now we have all methods, so decorate each of them
            for name in funcs:
                def caller(self, *args,**kwargs):
                    """ calls all baseclass implementations """
                    for func in funcs[name]:
                        func(self, *args,**kwargs)
                attrs[name] = caller
    
            return type.__new__(meta, clsname, bases, attrs)
    
    class B:
        def fn(self):
            print 'B'
    
    class A:
        def fn(self):
            print 'A'
    
    class C(A,B, object):
        __metaclass__=CallAll
    
    c=C()
    c.fn()
    

    【讨论】:

    • 我实际上比我更喜欢 THC4k 的解决方案。 :D 鉴于 OP 的资格,他宁愿避免 super(),这似乎更适合。但是,AFAIK,元类仅适用于新型类。不过,对 nikow 和 extraneon 的看法 +1。
    【解决方案2】:

    元类是一种可能的解决方案,但有些复杂。 super 可以非常简单地做到这一点(当然,使用新样式类:没有理由在新代码中使用旧类!):

    class B(object):
        def fn(self):
            print 'B'
            try: super(B, self).fn()
            except AttributeError: pass
    
    class A(object):
        def fn(self):
            print 'A'
            try: super(A, self).fn()
            except AttributeError: pass
    
    class C(A, B): pass
    
    c = C()
    c.fn()
    

    您需要 try/except 来支持单继承或多继承的任何顺序(因为在某些时候将没有进一步的基础方法解析顺序,MRO,定义一个名为 fn 的方法,您需要捕获并忽略生成的AttributeError)。但是正如您所看到的,与您根据您对不同答案的评论所认为的不同,您不一定需要在最叶的类中覆盖fn,除非您需要在这样的覆盖中对该类执行特定的操作-- super 在纯继承(非覆盖)方法上也能正常工作!

    【讨论】:

      【解决方案3】:

      我个人不会尝试使用装饰器这样做,因为使用新样式的类和super(),可以实现以下目标:

      >>> class A(object):
      ...     def __init__(self):
      ...         super(A, self).__init__()
      ...         print "A"
      ... 
      >>> class B(object):
      ...     def __init__(self):
      ...         super(B, self).__init__()
      ...         print "B"
      ... 
      >>> class C(A, B):
      ...     def __init__(self):
      ...         super(C, self).__init__()
      ... 
      >>> foo = C()
      B
      A
      

      我想方法调用会以同样的方式工作。

      【讨论】:

      • 但是,在这里我仍然必须定义派生类中的每个函数。它们将是单行函数,例如 def fn(self): super(C, self).fn(),但我仍然必须为每个函数编写它。我正在寻找的是一种避免这种情况的方法。此外,为此,我必须让每个班级都成为新式班级。
      • 无论如何你都应该使用新的样式类。超级是要走的路。
      • @Nikwin 构造函数继承被设计在python之外,所以如果你想在派生类中使用构造函数逻辑,是的,你必须显式调用构造函数。 Explicit 是 python 游戏的名称,我不能说我发现这是个坏事 :)
      • @extraneon:我不担心构造函数,我想要的是派生类的函数调用所有同名的基类函数。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-14
      • 2013-03-30
      • 2020-09-10
      • 1970-01-01
      • 1970-01-01
      • 2019-08-05
      • 1970-01-01
      相关资源
      最近更新 更多