3

CallableWrappingMeta新しいクラスの本体を歩き、そのメソッドをクラスでラップするメタクラスがあるとしましょうInstanceMethodWrapper:

import types

class CallableWrappingMeta(type):
    def __new__(mcls, name, bases, cls_dict):
        for k, v in cls_dict.iteritems():
            if isinstance(v, types.FunctionType):
                cls_dict[k] = InstanceMethodWrapper(v)
        return type.__new__(mcls, name, bases, cls_dict)

class InstanceMethodWrapper(object):
    def __init__(self, method):
        self.method = method
    def __call__(self, *args, **kw):
        print "InstanceMethodWrapper.__call__( %s, *%r, **%r )" % (self, args, kw)
        return self.method(*args, **kw)

class Bar(object):
    __metaclass__ = CallableWrappingMeta
    def __init__(self):
        print 'bar!'

ダミーのラッパーは、引数が入ってくるとそれを出力するだけです。しかし、何か目立つことに気付くでしょう: メソッドはインスタンス オブジェクト レシーバーに渡されInstanceMethodWrapperません。クラスの作成中 (メタクラスが処理された後) にインスタンス メソッドに変換されます。

考えられる解決策は、クラスの代わりにデコレータを使用してメソッドをラップすることです。その関数はインスタンス メソッドになります。しかし、実際にInstanceMethodWrapperは はもっと複雑です。API を提供し、メソッド呼び出しイベントを発行します。クラスはより便利です (そしてパフォーマンスは向上しますが、これはそれほど重要ではありません)。

私もいくつかのデッドエンドを試しました。サブクラスtypes.MethodType化して、types.UnboundMethodTypeどこにも行きませんでした。少し内省すると、彼らはtype. そのため、両方をメタクラスとして使用してみましたが、どちらもうまくいきませんでした。メタクラスとして特別な要求があるのか​​もしれませんが、現時点では文書化されていない領域にいるようです。

何か案は?

4

4 に答える 4

0

編集:私はもう一度嘘をつきます。関数の属性は読み取り専用ですが、割り当てたときに__?attr__常に例外をスローするとは限らないようです。AttributeException私は知らないよ。振り出しに戻って!

編集:ラッピング関数は属性要求をにプロキシしないため、これは実際には問題を解決しませんInstanceMethodWrapper。もちろん、デコレータの属性をダックパンチすることもでき__?attr__ますが、それは私が今行っていることですが、それは醜いです。より良いアイデアは大歓迎です。


もちろん、私はすぐに、単純なデコレータをクラスと組み合わせるとうまくいくことに気付きました。

def methodize(method, callable):
    "Circumvents the fact that callables are not converted to instance methods."
    @wraps(method)
    def wrapper(*args, **kw):
        return wrapper._callable(*args, **kw)
    wrapper._callable = callable
    return wrapper

InstanceMethodWrapper次に、メタクラスのtoの呼び出しにデコレータを追加します。

cls_dict[k] = methodize(v, InstanceMethodWrapper(v))

プーフ。少し斜めですが、動作します。

于 2009-05-03T00:26:02.747 に答える
0

クラス内のすべてのメソッドをカスタム関数でラップするメタクラスを作成しようとしていると思います。

これが私のバージョンで、少し斜めではないと思います。

import types

class CallableWrappingMeta(type):
    def __new__(mcls, name, bases, cls_dict):
        instance = type.__new__(mcls, name, bases, cls_dict)
        for k in dir(instance):
            v = getattr(instance, k)
            if isinstance(v, types.MethodType):
                setattr(instance, k, instanceMethodWrapper(v))

        return instance

def instanceMethodWrapper(function):
    def customfunc(*args, **kw):
        print "instanceMethodWrapper(*%r, **%r )" % (args, kw)
        return function(*args, **kw)
    return customfunc

class Bar(object):
    __metaclass__ = CallableWrappingMeta

    def method(self, a, b):
        print a,b

a = Bar()
a.method("foo","bar")
于 2009-05-03T01:41:18.230 に答える
0

あなたの問題についてもっと具体的にする必要があると思います。元の質問は関数のラッピングについて話していますが、その後の回答は関数属性の保存について話しているようで、これは新しい要因のようです。設計目標をより明確に説明すると、質問への回答が容易になる場合があります。

于 2009-05-03T13:53:23.010 に答える