复制签名,转发包装函数中的所有参数

时间:2017-02-23 16:09:37

标签: python function signature

我在课程中有两个函数,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()相同的签名和默认参数,并将所有参数转发给它。

任何提示?

4 个答案:

答案 0 :(得分:7)

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)

现在,如果您在提供IDLE等自动完成功能的shell中使用show,您会看到show而不是加密*args, **kwargs

的正确参数

答案 1 :(得分:2)

您可以使用参数打包/解包:

def show(self, *args, **kwargs):
    from matplotlib import pyplot as plt
    self.plot(*args, **kwargs)
    plt.show()

答案 2 :(得分:1)

扩展Serge的答案,我将提出以下建议:

from inspect import signature

# create a decorator to copy signatures
def copy_signatue(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(forward).bind(*args, **kwds) 
    # now do potentially complicated and obscuring tasks
    print('Just wrapping') 
    test(*args, **kwds)

调用signature(forward).bind(*args, **kwds)可确保使用正确的参数调用该函数。如果您有复杂的函数,则在调用函数之前检查参数会使错误更清晰。

我故意没有在装饰器中包括支票。否则,我们将需要另一个函数调用,这会使调试更加复杂。

答案 3 :(得分:0)

基于DerWeh的answer(在此页面中):

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