【问题标题】:How to optionally pass arguments with non-default values in Python?如何在 Python 中选择性地传递具有非默认值的参数?
【发布时间】:2017-02-14 03:02:00
【问题描述】:

我有以下方法:

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)

有什么更高效、更花哨和 Pythonic 的方式来解决我的问题?

【问题讨论】:

    标签: python syntactic-sugar


    【解决方案1】:
    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"

    【讨论】:

    • 构建dict 可能会更简洁一点:arg_dict = {k: v for k, v in zip(('b', 'c', 'd'), (user_b, user_c, user_d)) if v is not None} 但是是的,它永远不会很漂亮。
    【解决方案2】:

    这是 tdelaney's answer 的一个细微变化(+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
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 做这件事的装饰器可能会更好。
      • 另外,至少在 Python 3 上,我认为您需要使用 kw.items() 而不是 kw
      • @tagc - 你是绝对正确的。我修复了这个错误,但既然你已经跳进去完成了装饰器,我就把那个留给你!
      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 2013-02-20
        • 1970-01-01
        • 2011-04-15
        • 2021-09-24
        • 1970-01-01
        • 2012-08-01
        • 1970-01-01
        • 2017-04-23
        • 1970-01-01
        相关资源
        最近更新 更多