2

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

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)
4

5 回答 5

1

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

def func2(b=None):
    if b is None:
        return func1()
    else:
        return func1(b)
于 2014-09-09T15:59:41.870 回答
1

我怀疑正确的方法是让你的func2函数使用一个哨兵值作为它的默认参数,这样你就可以很容易地识别它。如果你得到那个哨兵,你可以设置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在所有情况下都使用参数调用它,要么在所有情况下都调用它而不使用参数。您很少需要有条件地传递这样的参数。

于 2014-09-09T16:23:57.680 回答
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)or func2(b=y)。几乎在每种情况下,唯一对象哨兵都足以避免必须真正保证它是如何被调用的,但它可以做到。

但是从您立即返回结果的事实来看func1,我认为没有理由func2甚至有默认参数。在默认调用 ( func2()) 中,y从不使用。那么它为什么会存在呢?为什么不直接使用 definefunc2(*a, **k)并将它们传递给func1

于 2014-09-09T16:41:41.787 回答
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)
于 2014-09-09T16:05:15.347 回答
0

您的确切用例是什么? func2应该足够聪明,只将适当的参数传递给func1,并且应该依赖于任何参数的默认值。

我唯一一次发现有必要改变func2调用func1方式是什么时候func1是一个c带有古怪签名的函数:

def func2(this, that, those=None):
    if those is None:
        return func1(this, that)
    else:
        return func1(this, that, those)
于 2014-09-09T16:49:42.187 回答