質問
新しいクラスの本体を歩くメタクラス 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
から派生しているようです。そこで、両方をメタクラスとして使用してみましたが、運もありません。メタクラスとして特別な要求がある場合もありますが、現時点ではドキュメント化されていない領域にいるようです。
アイデアはありますか
解決
InstanceMethodWrapper
クラスを __ get __
(これは return self
だけで十分に可能です)で強化します-つまり、そのクラスをインスタンスが記述子オブジェクトであるように、記述子タイプ。 http://users.rcn.com/python/download/Descriptor.htmを参照してください背景と詳細。
ところで、Python 2.6以上を使用している場合は、そのメタクラスの代わりにクラスデコレータを使用することを検討してください-非常に多くのメタクラスがそのような装飾目的で使用されているため、クラスデコレータを追加しました使いやすい。
他のヒント
編集:もう一度うそをつきます。関数の __?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")
問題についてより具体的にする必要があると思います。元の質問は関数のラッピングについて述べていますが、その後の答えは関数の属性を保存することについて述べているようで、これは新しい要因のようです。設計目標をより明確に記述した場合、質問に答える方が簡単かもしれません。