如何在Python中选择性地传递具有非默认值的参数



我有以下方法:

def a(b='default_b', c='default_c', d='default_d'):
    # …
    pass

我有一些命令行界面,可以提供变量user_buser_cuser_d,也可以将它们设置为None,即简单的Python argparse模块。

我想打一个类似的电话:

a(b=user_b if user_b is not None,
  c=user_c if user_c is not None,
  d=user_d if user_d is not None)

如果变量是None,我希望使用方法参数中的默认值。

我找到的唯一方法是检查用户变量的所有组合:

if not user_b and not user_c and not user_d:
    a()
elif not user_b and not user_c and user_d:
    a(d)
…
elif user_b and user_c and user_d:
    a(b, c, d)

什么是更有效、更奇特、更Python的方法来解决我的问题?

arg_dict = {}
if user_b is not None:
    arg_dict["b"] = user_b
if user_c is not None:
    arg_dict["c"] = user_c
if user_d is not None:
    arg_dict["d"] = user_d
a(**arg_dict)

不过不太好看。

一个更好的方法是重新编写函数a,接受None作为默认答案,然后进行检查。(即if b is None: b = "default_b"(

下面是tdelaney答案的一个细微变化(对它的+1表示启动(,它通过用另一个函数装饰a来工作,该函数删除传递给装饰对象的所有值为None的关键字参数。

from functools import wraps

# You can reuse this decorator for all functions that might be
# invoked in your CLI that should handle their arguments like
# 'a' does.
def scrub_parameters(f):
    @wraps(f)
    def wrapper(**kwargs):
        kwargs = {k: v for k, v in kwargs.items() if v is not None}
        return f(**kwargs)
    return wrapper

@scrub_parameters
def a(b='default_b', c='default_c', d='default_d'):
    print('b={}, c={}, d={}'.format(b, c, d))

if __name__ == '__main__':
    arg_dict = {'b': 'user_b', 'c': 'user_c', 'd': None}
    a(**arg_dict)  # b=user_b, c=user_c, d=default_d
    arg_dict = {'b': None, 'c': 'user_c', 'd': None}
    a(**arg_dict)  # b=default_b, c=user_c, d=default_d

您可以编写一个函数来过滤掉不需要的值,然后使用它来清除目标函数调用。

def scrub_params(**kw):
    return {k:v for k,v in kw.items() if v is not None}
some_function(**scrub_params(foo=args.foo, bar=args.bar))

您可以用数据定义一个类,并将对象作为参数传递。

class Args:
    def __init__(self, user_b, user_c, user_d):
        self.b = user_b
        self.c = user_c
        self.d = user_d

最新更新