以前の回答と矛盾して、この質問にもう一度回答します。
短い答え: はい! (ちょっと)
メソッドデコレーターの助けを借りて、これが可能です。コードは長くてやや醜いですが、使い方は短くて簡単です。
問題は、デフォルトの引数としてバインドされていないメソッドしか使用できないことです。では、実際の関数を呼び出す前に引数をバインドするラッピング関数 (デコレータ) を作成するとどうなるでしょうか?
まず、このタスクを実行できるヘルパー クラスを作成します。
from inspect import getcallargs
from types import MethodType
from functools import wraps
class MethodBinder(object):
def __init__(self, function):
self.function = function
def set_defaults(self, args, kwargs):
kwargs = getcallargs(self.function, *args, **kwargs)
# This is the self of the method we wish to call
method_self = kwargs["self"]
# First we build a list of the functions that are bound to self
targets = set()
for attr_name in dir(method_self):
attr = getattr(method_self, attr_name)
# For older python versions, replace __func__ with im_func
if hasattr(attr, "__func__"):
targets.add(attr.__func__)
# Now we check whether any of the arguments are identical to the
# functions we found above. If so, we bind them to self.
ret = {}
for kw, val in kwargs.items():
if val in targets:
ret[kw] = MethodType(val, method_self)
else:
ret[kw] = val
return ret
したがって、 のインスタンスはMethodBinder
メソッド (またはメソッドになる関数) に関連付けられます。MethodBinder
s メソッドには、関連付けられset_defaults
たメソッドを呼び出すために使用される引数を指定できます。関連付けられたメソッドのバインドされていないメソッドをバインドし、関連付けられたメソッドを呼び出すために使用できる kwargs dict を返します。self
これで、このクラスを使用してデコレータを作成できます。
def bind_args(f):
# f will be b in the below example
binder = MethodBinder(f)
@wraps(f)
def wrapper(*args, **kwargs):
# The wrapper function will get called instead of b, so args and kwargs
# contains b's arguments. Let's bind any unbound function arguments:
kwargs = binder.set_defaults(args, kwargs)
# All arguments have been turned into keyword arguments. Now we
# may call the real method with the modified arguments and return
# the result.
return f(**kwargs)
return wrapper
醜さを忘れたので、シンプルできれいな使用法を示しましょう。
class demo(object):
def a(self):
print("{0}.a called!".format(self))
@bind_args
def b(self, param=a):
param()
def other():
print("other called")
demo().b()
demo().b(other)
このレシピでは、Python に新しく追加さgetcallargs
れinspect
た . python2.7 および 3.1 の新しいバージョンでのみ使用できます。