3

如果我有这个功能:

def foo(arg_one, arg_two):
    pass

我可以像这样包装它:

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

foo = bar

是否有可能在不知道 foo 所需参数的情况下做到这一点,如果可以,怎么做?

4

4 回答 4

5

您可以使用参数解包运算符(或任何它们被称为的):

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

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

于 2013-06-26T18:57:37.783 回答
4

您可以使用*args**kwargs

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

args是位置参数的列表。

kwargs是关键字参数的字典。

请注意,调用这些变量args只是kwargs一个命名约定。***尽一切可能解开论点。

另见:

于 2013-06-26T18:57:04.067 回答
2

这是另一个稍微通用的用例(除了 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 机制是多么灵活(!)。

于 2013-06-26T19:34:13.977 回答
0

除了alecxe 的回答之外,如果您希望您的包装器保留签名(换句话说,它的用户看起来好像它是包装的函数),您可能希望看看functools.wraps它的替代品makefun.wraps,这可以解决一些缺点并将其用途扩展到您想要修改签名的情况。有关差异的简短说明,请参见此处。顺便说一句,我是作者makefun;)

这是你将如何编码:

from makefun import wraps

@wraps(foo)
def bar(*args, **kwargs):
    return foo(*args, **kwargs)
于 2019-03-13T22:21:51.217 回答