質問

新しいクラスの本体を歩くメタクラス 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 ははるかに複雑です。APIを提供し、メソッド呼び出しイベントを公開します。クラスの方が便利です(パフォーマンスが向上しますが、これが重要なことではありません)。

私も行き止まりを試しました。 types.MethodType および types.UnboundMethodType のサブクラス化はどこにも行きませんでした。少し内省し、 type から派生しているようです。そこで、両方をメタクラスとして使用してみましたが、運もありません。メタクラスとして特別な要求がある場合もありますが、現時点ではドキュメント化されていない領域にいるようです。

アイデアはありますか

役に立ちましたか?

他のヒント

編集:もう一度うそをつきます。関数の __?attr __ 属性は読み取り専用ですが、割り当てたときに常に AttributeException 例外をスローするとは限りませんか?私は知らないよ。スクエア1に戻ります。

編集:ラッピング関数は 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 の呼び出しにデコレーターを追加します。

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

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

あなたは、クラス内のすべてのメソッドをカスタム関数でラップするメタクラスを作成しようとしていると推測しています。

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

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")

問題についてより具体的にする必要があると思います。元の質問は関数のラッピングについて述べていますが、その後の答えは関数の属性を保存することについて述べているようで、これは新しい要因のようです。設計目標をより明確に記述した場合、質問に答える方が簡単かもしれません。

scroll top