在方法中复制函数签名



我试图创建一个函数Bar.bar与签名和文档复制(OP)从foo:

from inspect import signature
import functools
from typing import Callable
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)
tgt.__signature__ = signature(signature_source)
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 Bar:
@deco_meta_copy_signature(foo)
def bar(self):
pass
b = Bar()
print('Signature 2)', signature(b.bar))

打印:

Signature 1) (a, b, c=0, d=1, **kwargs)
Signature 2) (b, c=0, d=1, **kwargs)

签名2中可以看出,第一个参数不被保留。我认为这与目标函数是一个方法和接收self参数有关。如何在拥有所有其他参数的同时将self添加到签名中?

下面的工作,但它是通过更新一个"private"Signature类的_parameters成员,这是我对未来的免责声明。

装饰器查看目标的签名,如果第一个参数名为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)

最新更新