有条件地向函数传递任意数量的默认命名参数

13

有没有可能有条件地向Python函数传递任意数量的命名默认参数?

例如,有一个函数:

def func(arg, arg2='', arg3='def')

现在的逻辑是我有一个条件来确定是否需要传递arg3,我可以这样做:

if condition == True:
    func('arg', arg2='arg2', arg3='some value')
else:
    func('arg', arg2='arg2')
问题是,我能否使用以下这种简写方式:
func('arg', 'arg2', 'some value' if condition == True else # nothing so default gets picked
)
4个回答

10

我能想到的唯一方法是

func("arg", "arg2", **({"arg3": "some value"} if condition == True else {}))
或者
func("arg", "arg2", *(("some value",) if condition == True else ()))

但请不要这样做。使用你自己提供的代码,或者类似这样的代码:

if condition:
   arg3 = "some value",
else:
   arg3 = ()
func("arg", "arg2", *arg3)

2
你对*有什么意见? - Erin
2
没有任何反对 *** 的意思。我只是认为原始代码更易读。我认为我不喜欢 a if c else b - Sven Marnach
1
或者,可以使用一些条件逻辑(在函数调用之外)来构建参数字典。然后可以使用 ** 传递它们。这种方法在有大量参数时仍然易读。 - Wilduck

9

那不是有效的Python语法,你必须在else后面加上一些内容。通常做法是:

func('arg', 'arg2', 'some value' if condition else None)

并且函数定义也相应地进行了更改:

def func(arg, arg2='', arg3=None):
    arg3 = 'def' if arg3 is None else arg3

5
如果您有一个具有许多默认参数的函数
def lots_of_defaults(arg1 = "foo", arg2 = "bar", arg3 = "baz", arg4 = "blah"):
    pass

如果您希望根据程序中其他操作的情况传递不同的值到某些位置,那么一个简单的方法是使用**来解包一个参数名和值的字典,该字典是基于程序逻辑构建的。

different_than_defaults = {}
if foobar:
    different_than_defaults["arg1"] = "baaaz"
if barblah:
    different_than_defaults["arg4"] = "bleck"

lots_of_defaults(**different_than_defaults)

这样做的好处是,在调用函数时不会使你的代码混乱,如果在你的调用中有很多逻辑来确定调用的内容。如果有任何没有默认值的参数,请在传递字典之前包含您要传递的值。


0

你可以编写一个帮助函数

def caller(func, *args, **kwargs):
    return func(*args, **{k:v for k,v in kwargs.items() if v != caller.DONT_PASS})
caller.DONT_PASS = object()

使用此函数调用另一个函数,并使用 caller.DONT_PASS 指定您不想传递的参数。
caller(func, 'arg', 'arg2', arg3 = 'some value' if condition else caller.DONT_PASS)

请注意,此caller()仅支持有条件地传递关键字参数。要支持位置参数,您可能需要使用模块inspect来检查函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接