【问题标题】:Python wrap function with unknown arguments带有未知参数的 Python 包装函数
【发布时间】:2013-06-26 18:55:50
【问题描述】:

如果我有这个功能:

def foo(arg_one, arg_two):
    pass

我可以这样包装:

def bar(arg_one, arg_two):
    return foo(arg_one, arg_two)

foo = bar

是否可以在不知道 foo 所需参数的情况下执行此操作,如果可以,如何操作?

【问题讨论】:

    标签: python function arguments


    【解决方案1】:

    您可以使用参数解包运算符(或任何they're called):

    def bar(*args, **kwargs):
        return foo(*args, **kwargs)
    

    如果您不打算传递任何关键字参数,您可以删除 **kwargs

    【讨论】:

    • 虽然离开它并没有什么坏处,它以后可能会派上用场。
    【解决方案2】:

    您可以使用*args**kwargs

    def bar(*args, **kwargs):
        return foo(*args, **kwargs)
    

    args 是位置参数列表。

    kwargs 是关键字参数的字典。

    请注意,调用这些变量 argskwargs 只是一种命名约定。 *** 为解包参数发挥了所有作用。

    另见:

    【讨论】:

    • 啊,谢谢,我以为 **kwargs 可能是相关的,但我不知道 *args,所以无法弄清楚。
    【解决方案3】:

    这是另一个稍微通用的用例(除了 Blender 的回答):

    通常在 OOP 中扩展对象时,实际上需要重写方法并(小心地)扩展甚至更改签名(扩展方法的参数的顺序和数量),例如在__init__() 作为对象构造函数的方法中。

    这里是一个如何应用 *args, **kwds 的例子:

    class Foo(object):
        def __init(self, foo_positional_arg, foo_optional_arg=None):
            pass
    
    
    class Bar(Foo):
    
        def __init__(self, bar_postional_arg, bar_optional_arg=None, *args, **kwds):
            self.bar_postional_arg = bar_postional_arg
            self.bar_optional_arg = bar_optional_arg
            super(Bar, self).__init__(*args, **kwds)
    

    事实上,实际上确实可以更改签名的顺序或从前一个(包装的)完整或部分签名中捕获参数。

    def __init__(self, bar_postional_arg, foo_positional, foo_optional_arg=False, bar_optional_arg=None, *args, **kwds):
    

    这再次证明了 python 函数(和方法)中的 *args、**kwds 机制是多么灵活(!)。

    【讨论】:

      【解决方案4】:

      除了alecxe's answer,如果你希望你的包装器保留签名(换句话说,它的用户看起来好像它是被包装的函数),你可能希望看看functools.wraps和它的替换makefun.wraps,它修复了一些缺点并将其使用范围扩展到您想要修改签名的情况。有关差异的简短说明,请参阅here。顺便说一句,我是makefun的作者;)

      这就是你的编码方式:

      from makefun import wraps
      
      @wraps(foo)
      def bar(*args, **kwargs):
          return foo(*args, **kwargs)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-21
        • 2022-11-15
        • 2022-08-09
        • 1970-01-01
        • 1970-01-01
        • 2020-12-06
        • 2015-10-19
        • 1970-01-01
        相关资源
        最近更新 更多