下面的方法可以工作,但它是通过更新“private”成员来实现的,
_parameters
,当然
Signature
这是我对未来的免责声明。
装饰程序查看目标的签名,以及是否有名为
self
,则如果复制源的签名并在前面加上附加参数:
from inspect import signature, Parameter
import functools
from typing import Callable
from types import MappingProxyType
from collections import OrderedDict
from copy import deepcopy
def deco_meta_copy_signature(signature_source: Callable):
def deco(target: Callable):
@functools.wraps(target)
def tgt(*args, **kwargs):
signature(signature_source).bind(*args, **kwargs)
return target(*args, **kwargs)
sig_s = signature(signature_source)
sig_t = signature(target)
parameters = sig_t.parameters
if len(parameters):
# get first parameter
it = iter(parameters)
param0 = next(it)
if param0 == 'self':
#add extra dummy parameter that will be discarded:
d = OrderedDict()
d['dummy'] = Parameter('dummy', Parameter.POSITIONAL_OR_KEYWORD)
d['self'] = Parameter('self', Parameter.POSITIONAL_OR_KEYWORD)
for k, v in sig_s.parameters.items():
d[k] = v
sig_s = deepcopy(sig_s) # leave actual signature unmodified
sig_s._parameters = MappingProxyType(d) # accessing "private" member: beware!
tgt.__signature__ = sig_s
tgt.__doc__ = signature_source.__doc__
print('Signature 1)', signature(tgt))
return tgt
return deco
def foo(a, b, c=0, d=1, **kwargs):
""" foo! """
pass
class Action:
def doit(self, x=9):
pass
edit = Action()
class Bar:
@deco_meta_copy_signature(foo)
def bar(self):
pass
@deco_meta_copy_signature(edit.doit)
def foo(self):
pass
@deco_meta_copy_signature(foo)
def bar(x=8):
pass
@deco_meta_copy_signature(edit.doit)
def foo(x=8):
pass
b = Bar()
print('Signature 2)', signature(b.bar))
print('Signature 3)', signature(b.foo))
print('Signature 4)', signature(bar))
print('Signature 5)', signature(foo))
印刷品:
Signature 1) (dummy, self, a, b, c=0, d=1, **kwargs)
Signature 1) (dummy, self, x=9)
Signature 1) (a, b, c=0, d=1, **kwargs)
Signature 1) (x=9)
Signature 2) (self, a, b, c=0, d=1, **kwargs)
Signature 3) (self, x=9)
Signature 4) (a, b, c=0, d=1, **kwargs)
Signature 5) (x=9)