2

クラスがあるとしましょう

class Foo:
    def __init__(self):
        pass
    def meth1(self, *args):
        do_stuff()
    def meth2(self, **kwargs):
        more_stuff()
    def callme(self):
        print "I'm called!"

を実行しcallme()た後に呼び出されるようにスマートに変更したいと思います。それ、どうやったら出来るの?私はクラス デコレータもメタクラスも使用したことがないので、どちらが正しい方法なのか、またそれらを適切に使用する方法がわかりません。meth1meth2

メタクラスを使用して、次のことをまとめました。

from types import FunctionType
def addcall_meta(name, bases, dct):
    newdct = dict(dct)
    for k, v in dct.items():
        if isinstance(v, FunctionType) and k not in ('__metaclass__', 'callme'):
            # the above can include more filters such as not startswith, etc.
            print k, 'is a function!'
            def newmethod(self, *args, **kwargs):
                v(self, *args, **kwargs)
                dct['callme'](self)
            newdct[k] = newmethod
    return type(name, bases, newdct)

クラス デコレータを使用する場合:

def addcall_deco(cls):
    dct = {}
    for k, v in cls.__dict__.items():
        if isinstance(v, FunctionType) and k != 'callme':
            def newv(self, *args, **kwargs):
                v(self, *args, **kwargs)
                self.callme()
            cls.k = newv
    return cls

どちらも私の非常に単純な例ではうまくいくようです:

In [75]: Foo()
I'm called!
Out[75]: <__main__.Foo instance at 0x21ed680>

一方を使用し、他方を使用しない明らかな理由はありますか (特定のコーナー ケースなど)。また、何とか使用できると思い__new__ますが、常識的な観点から、すべてのインスタンスではなく、クラスを変更したいと考えています。

4

2 に答える 2

2

古いバージョンの Python はクラス デコレータをサポートしていないため、下位互換性が懸念される場合は、メタクラスを使用するか、クラス デコレータをクラスをラップする関数呼び出しに変換する必要があります。

于 2012-09-01T16:46:16.493 に答える
1

実際、ここではメタクラスをクラス デコレータとして使用しています。メタクラスで許可されているより柔軟なものは実際には必要ありません。

したがって、両方の実装が同じであるため、より単純なアプローチ (クラス デコレータ) を使用する必要があります。「下位互換性」に関しては、新しいプロジェクトで心配する必要がある問題ではありません。

もちろん、多くのサーバーは「長期サポート」エディションのために非常に古い Linux を実行しており、バージョン 2.4 または 2.5 の Python を備えていますが、プロジェクトが実際にそのような古いサーバーで使用されている場合は、ユーザーは、通常のユーザーとして Python をサポートするのに十分な更新をいつでもインストールできます。システムの Python を使用する必要はありません。

余談ですが、ラップされたメソッドの戻り値がある場合は、それを破棄していることに注意してください。それを行う方法は次のとおりです。

 def newv(self, *args, **kwargs):
      result = v(self, *args, **kwargs)
      self.callme()
      return result

そして最後に、あなたが扱っているプロジェクトでこの種のアプローチがたくさん必要になると思うなら、「アスペクト指向プログラミング」を見てください。ツールチェーンまたは作業方法の多くの変更。

于 2012-09-07T22:29:19.763 に答える