1

基本的に、私が欲しいのはこれを行うことです:

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デコレータをどのように実装しますか?

4

3 に答える 3

4

これはデコレータの仕事ではありません。クラスの通常の動作を完全に変更したいので、これは実際にはメタクラスの仕事です。

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()
于 2009-12-07T15:11:41.810 に答える
1

個人的には、新しいスタイルのクラスとを使用するため、デコレータでこれを実行しようとはしません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

メソッド呼び出しも同じように機能すると思います。

于 2009-12-07T13:13:08.903 に答える
1

メタクラスは可能な解決策ですが、やや複雑です。 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動作します純粋に継承された (オーバーライドされていない) メソッドでも問題ありません。

于 2009-12-07T17:09:47.687 に答える