复制签名,转发包装函数的所有参数
Copy signature, forward all arguments from wrapper function
我在 class、plot()
和 show()
中有两个函数。 show()
,作为一种方便的方法,除了在 plot()
的代码中添加两行之外什么都不做,比如
def plot(
self,
show_this=True,
show_that=True,
color='k',
boundary_color=None,
other_color=[0.8, 0.8, 0.8],
show_axes=True
):
# lots of code
return
def show(
self,
show_this=True,
show_that=True,
color='k',
boundary_color=None,
other_color=[0.8, 0.8, 0.8],
show_axes=True
):
from matplotlib import pyplot as plt
self.plot(
show_this=show_this,
show_that=show_that,
color=color,
boundary_color=boundary_color,
other_color=other_color,
show_axes=show_axes
)
plt.show()
return
一切正常。
我遇到的问题是 包装器中的代码似乎 show()
太多了。我真正想要的是:让 show()
具有与 plot()
相同的签名和默认参数,并将所有参数转发给它。
有什么提示吗?
您可以使用参数 packing/unpacking:
def show(self, *args, **kwargs):
from matplotlib import pyplot as plt
self.plot(*args, **kwargs)
plt.show()
Python 3 提供了使用 inspect 模块实际复制包装函数签名的能力:
def show(self, *args, **kwargs):
from matplotlib import pyplot as plt
self.plot(*args, **kwargs)
plt.show()
show.__signature__ = inspect.signature(plot)
现在,如果您在 shell 中使用显示,它提供像 IDLE 一样的自动完成,您将看到 show
的正确参数,而不是密码 *args, **kwargs
扩展 的回答我会提出以下建议:
from inspect import signature
# create a decorator to copy signatures
def copy_signature(source_fct):
def copy(target_fct):
target_fct.__signature__ = signature(source_fct)
return target_fct
return copy
# create a short test function as example
def test(a, /, b, c=2, *, d, e):
print(a, b, c, d, e)
# now wrap it
@copy_signature(test)
def forwards(*args, **kwds):
# assert that arguments are correct
signature(forwards).bind(*args, **kwds)
# now do potentially complicated and obscuring tasks
print('Just wrapping')
test(*args, **kwds)
调用 signature(forwards).bind(*args, **kwds)
确保使用正确的参数调用函数。如果你有复杂的函数,在调用函数之前检查参数可以使错误更清楚。
我故意没有在装饰器中包含支票。否则我们将需要另一个函数调用,这会使调试变得更加复杂。
基于 DerWeh 的 (在本页中):
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)
return tgt
return deco
我在 class、plot()
和 show()
中有两个函数。 show()
,作为一种方便的方法,除了在 plot()
的代码中添加两行之外什么都不做,比如
def plot(
self,
show_this=True,
show_that=True,
color='k',
boundary_color=None,
other_color=[0.8, 0.8, 0.8],
show_axes=True
):
# lots of code
return
def show(
self,
show_this=True,
show_that=True,
color='k',
boundary_color=None,
other_color=[0.8, 0.8, 0.8],
show_axes=True
):
from matplotlib import pyplot as plt
self.plot(
show_this=show_this,
show_that=show_that,
color=color,
boundary_color=boundary_color,
other_color=other_color,
show_axes=show_axes
)
plt.show()
return
一切正常。
我遇到的问题是 包装器中的代码似乎 show()
太多了。我真正想要的是:让 show()
具有与 plot()
相同的签名和默认参数,并将所有参数转发给它。
有什么提示吗?
您可以使用参数 packing/unpacking:
def show(self, *args, **kwargs):
from matplotlib import pyplot as plt
self.plot(*args, **kwargs)
plt.show()
Python 3 提供了使用 inspect 模块实际复制包装函数签名的能力:
def show(self, *args, **kwargs):
from matplotlib import pyplot as plt
self.plot(*args, **kwargs)
plt.show()
show.__signature__ = inspect.signature(plot)
现在,如果您在 shell 中使用显示,它提供像 IDLE 一样的自动完成,您将看到 show
的正确参数,而不是密码 *args, **kwargs
扩展
from inspect import signature
# create a decorator to copy signatures
def copy_signature(source_fct):
def copy(target_fct):
target_fct.__signature__ = signature(source_fct)
return target_fct
return copy
# create a short test function as example
def test(a, /, b, c=2, *, d, e):
print(a, b, c, d, e)
# now wrap it
@copy_signature(test)
def forwards(*args, **kwds):
# assert that arguments are correct
signature(forwards).bind(*args, **kwds)
# now do potentially complicated and obscuring tasks
print('Just wrapping')
test(*args, **kwds)
调用 signature(forwards).bind(*args, **kwds)
确保使用正确的参数调用函数。如果你有复杂的函数,在调用函数之前检查参数可以使错误更清楚。
我故意没有在装饰器中包含支票。否则我们将需要另一个函数调用,这会使调试变得更加复杂。
基于 DerWeh 的
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)
return tgt
return deco