1. ホーム
  2. python

[解決済み] メソッドごとに何度も入力することなく、クラスのすべての関数を装飾する方法は?重複

2023-05-24 20:32:14

質問

例えば、私のクラスが多くのメソッドを持っていて、それらの一つ一つに私のデコレーターを適用したいとします。後で新しいメソッドを追加するとき、同じデコレーターを適用したいのですが、メソッド宣言の上に常に @mydecorator を書きたくありませんね?

もし私が __call__ というのが正しいのでしょうか?

重要です。 以下の例は、元の質問とは異なる問題を解決しているように見えます。

EDITです。 私はこの方法を示したいと思います、それは後でこの質問を見つけるだれでものための私の問題の同様のソリューションです、コメントで言及されたようにミキシンを使用しています。

class WrapinMixin(object):
    def __call__(self, hey, you, *args):
        print 'entering', hey, you, repr(args)
        try:
            ret = getattr(self, hey)(you, *args)
            return ret
        except:
            ret = str(e)
            raise
        finally:
            print 'leaving', hey, repr(ret)

次に、別の

class Wrapmymethodsaround(WrapinMixin): 
    def __call__:
         return super(Wrapmymethodsaround, self).__call__(hey, you, *args)

どのように解決するのですか?

クラスの属性を走査して callable を装飾する関数でクラスを装飾します。たまたま callable である可能性のあるクラス変数がある場合、これは間違った方法かもしれませんし、ネストしたクラスも装飾します (この点を指摘してくれた Sven Marnach に感謝します)。実装例 (これは特殊なメソッドを除外しないことに注意してください ( __init__ など) を除外しないことに注意してください)。

def for_all_methods(decorator):
    def decorate(cls):
        for attr in cls.__dict__: # there's propably a better way to do this
            if callable(getattr(cls, attr)):
                setattr(cls, attr, decorator(getattr(cls, attr)))
        return cls
    return decorate

このように使用します。

@for_all_methods(mydecorator)
class C(object):
    def m1(self): pass
    def m2(self, x): pass
    ...

Python 3.0と3.1では callable は存在しません。Python 2.x ではずっと存在していましたが、Python 3.2 では isinstance(x, collections.Callable) のラッパーとして Python 3.2 で復活したので、それを使うこともできます。 callable の置き換えが可能です。