デコレータは、単に別の関数で何かを行う関数です。したがって、技術的には、必要なコードをfoo
メソッドのすぐ下に置くことができ、技術的にfoo
は、デコレーターを使用せずに変更することになりますが、それはひどい混乱になります。
必要なことを行う最も簡単な方法は、2 番目の関数 (bar
この場合) を引数として取るデコレータを作成して、どの署名をコピーするかを知ることです。クラスコードは次のようになります。
class Blah(object):
@copy_argspec(bar)
def foo(self, *args, **kwargs):
""" a docstr """
result = bar(*args, **kwargs)
result = result**2 # just so it's clear we're doing something extra here...
return result
bar
クラスの後ではなく、前に定義する必要があります。
.
.
.
. . . 時間が経ちます。. . .
.
.
幸いなことに、適応できる古いデコレータを見つけました。
help(Blah.foo)
装飾前はこんな感じ。
Help on method foo in module __main__:
foo(self, *args, **kwargs) unbound __main__.Blah method
a docstr
装飾後は次のようになります。
Help on method foo in module __main__:
foo(self, x, y, z=1, q=2) unbound __main__.Blah method
a more useful docstr, saying what x,y,z,q do
使用したデコレータは次のとおりです。
import inspect
class copy_argspec(object):
"""
copy_argspec is a signature modifying decorator. Specifically, it copies
the signature from `source_func` to the wrapper, and the wrapper will call
the original function (which should be using *args, **kwds). The argspec,
docstring, and default values are copied from src_func, and __module__ and
__dict__ from tgt_func.
"""
def __init__(self, src_func):
self.argspec = inspect.getargspec(src_func)
self.src_doc = src_func.__doc__
self.src_defaults = src_func.func_defaults
def __call__(self, tgt_func):
tgt_argspec = inspect.getargspec(tgt_func)
need_self = False
if tgt_argspec[0][0] == 'self':
need_self = True
name = tgt_func.__name__
argspec = self.argspec
if argspec[0][0] == 'self':
need_self = False
if need_self:
newargspec = (['self'] + argspec[0],) + argspec[1:]
else:
newargspec = argspec
signature = inspect.formatargspec(
formatvalue=lambda val: "",
*newargspec
)[1:-1]
new_func = (
'def _wrapper_(%(signature)s):\n'
' return %(tgt_func)s(%(signature)s)' %
{'signature':signature, 'tgt_func':'tgt_func'}
)
evaldict = {'tgt_func' : tgt_func}
exec new_func in evaldict
wrapped = evaldict['_wrapper_']
wrapped.__name__ = name
wrapped.__doc__ = self.src_doc
wrapped.func_defaults = self.src_defaults
wrapped.__module__ = tgt_func.__module__
wrapped.__dict__ = tgt_func.__dict__
return wrapped