包装函数没有破坏默认参数

时间:2014-09-09 15:54:48

标签: python default-arguments

有没有办法转发函数参数而不隐藏原始调用是否提供可选参数的事实?

def func1(a=x):
    # do stuff

def func2(b=y):
    # pass args to func1 without masking func1 defaults
    return func1(?)

对func2()的调用应该导致func1()被调用而不带参数或者至少使用它的默认参数,无论它们是什么。

以下几乎可以正常工作,但从根本上说,我不知道func2是否有办法确定是否调用了默认值。

def func2(b=y):
    # this comes close but what if func2(y) is called?
    if b == y:
        return func1()
    else:
        return func1(b)

5 个答案:

答案 0 :(得分:1)

确定参数是否停止的常用方法是使用None作为默认值。您不太可能使用None调用函数,因此它是一个有用的标记。

def func2(b=None):
    if b is None:
        return func1()
    else:
        return func1(b)

答案 1 :(得分:1)

我怀疑正确的做法是让你的func2函数使用sentinel值作为默认参数,这样你就可以轻松识别它。如果你得到那个哨兵,你可以设置你要传递给func1但你想要的参数(例如没有传递任何参数)。您可以使用参数解包来处理传递可变数量的参数(例如0-1)。

一个普通的标记是None,但如果这对于调用者来说可能是一个有意义的值,你可能想要使用别的东西(object的实例是一个常见的选择)。这是一个例子:

def func1(a="default value"): # lets assume we don't know what this default is
    # do stuff with a

# later, perhaps in a different module

_sentinel = object()    # our sentinel object

def func2(b=_sentinel):
    if b is _sentinel:  # test for the sentinel
        b = "some useful value"
        a_args = ()     # arguments to func1 is an empty tuple
    else:
        a_args = (b,)   # pack b into a 1-tuple

    # do stuff with b perhaps

    func1(*a_args)      # call func1 with appropriate arguments (either b or nothing)

请注意,这种设计相对比较愚蠢。在大多数情况下,您可以在所有情况下使用参数调用func1,或者在所有情况下都可以在没有参数的情况下调用它。你很少需要有条件地传递这样的论点。

答案 2 :(得分:1)

看到这个答案:

https://stackoverflow.com/a/2088101/933416

无法从内部获取您想要的信息。要检测是否使用了默认值,您需要在函数中重新实现内部默认参数处理,即:

def func2(*args, **kwargs):
    if len(args) == 0 and "b" not in kwargs:
        b = y
        return func1()
    else:
        return func1(b)

现在,从第一次检查开始,我们保证调用func2()而不是func2(y)func2(b=y)。几乎在所有情况下,独特的对象哨兵都足以避免必须真正保证它的调用方式,但它可以完成。

但是从你返回 func1的结果这一事实判断,我认为没有理由func2甚至有默认参数。在默认调用(func2())中,永远不会使用y。那为什么呢?为什么不使用define func2(*a, **k)并将其直接传递给func1

答案 3 :(得分:0)

应使用可变参数完成参数转发:

def func2(*args, **kwargs):
    func1(*args, **kwargs)

尽管内省会受到一些影响,但一切都会奏效。


如果您有时不需要传递参数,则可以在以下情况下删除参数:

del kwargs["name"]

一个例子:

def print_wrapper(*args, extrabig=False, **kwargs):
    if extrabig:
        args = [arg*2 for arg in args]
        kwargs["sep"] = kwargs.get("sep", " ") * 2

    print(*args, **kwargs)

print_wrapper(2, 4, 8, end="!!!\n")
#>>> 2 4 8!!!

print_wrapper(2, 4, 8, sep=", ", end="!!!\n")
#>>> 2, 4, 8!!!

print_wrapper(2, 4, 8, extrabig=True, end="!!!\n")
#>>> 4  8  16!!!

如果你真的不想这样做(虽然你错了),你可以使用object来生成一个独特的哨兵。

# Bad! Won't let you print None
def optionally_print_one_thing(thing=None):
    if thing is not None:
        print(thing)

# Better
_no_argument = object()
def optionally_print_one_thing(thing=_no_argument):
    if thing is not _no_argument:
        print(thing)

答案 4 :(得分:0)

您的具体用例是什么? func2应该足够智能,只能将适当的参数传递给func1,这应该依赖于任何参数的默认值。

我唯一一次认为有必要更改func2调用func1的方式,func1c函数时带有棘手的签名:

def func2(this, that, those=None):
    if those is None:
        return func1(this, that)
    else:
        return func1(this, that, those)