代码之家  ›  专栏  ›  技术社区  ›  Adam

调用带有可选参数的方法最具Python风格的方法是什么?

  •  3
  • Adam  · 技术社区  · 11 年前

    假设我有一个带有一些可选参数的方法。

    def foo(a, b=1, c=2, d=3)

    如何调用它,以便在变量为None或空字符串时使用默认值?

    像下面这样的条件词似乎是一个可怕的解决方案:

    if b and not c and d:
        foo(myA, b = myB, d = myD)
    elif b and not c and not d:
        ...
    

    在Java中,我会选择工厂,但这似乎是默认情况下应该避免的。

    5 回复  |  直到 11 年前
        1
  •  7
  •   John Kugelman Michael Hodel    11 年前

    我会改变 foo 因此它将空值替换为默认值。

    def foo(a, b=None, c=None, d=None):
        if not b: b = 1
        if not c: c = 2
        if not d: d = 3
    

    请注意,这将把所有“false-y”值视为默认值,这不仅意味着 None '' 而且 0 , False , [] ,等等。就我个人而言,我会收紧接口并使用 没有一个 而且只有 没有一个 作为默认值。

    def foo(a, b=None, c=None, d=None):
        if b is None: b = 1
        if c is None: c = 2
        if d is None: d = 3
    
        2
  •  3
  •   Thijs van Dien    11 年前

    虽然我同意更改方法是一个更好的主意,但这里有一个替代方案,可以通过使用 dict 的参数,这些参数经过筛选然后被解压缩:

    d = {'b': myB, 'd': myD}
    foo(myA, **{k: d[k] for k in d if d[k]})
    

    当然 if d[k] 可以替换为 if d[k] not in {None, ''} 例如,它有一个稍微不同的含义(正如其他人所指出的)。

        3
  •  2
  •   inspectorG4dget Dillon Benson    11 年前

    如果你只想抓 None '' :

    def foo(a, b, c, d):
        blacklist = set([None, ''])
        if b in blacklist:
            b = 1
        if c in blacklist:
            c = 2
        if d in blacklist:
            d = 3
    

    如果您想捕获所有值v,使得 bool(v) False ,则:

    def foo(a, b, c, d):
        b = b or 1
        c = c or 2
        d = d or 3
    

    或者,您可以用另一个为您做断言的函数来修饰该函数(根据您的用例,这可能是过度的,也可能不是过度的)

        4
  •  2
  •   tdelaney    11 年前

    你可以调用一个函数来过滤掉你不想传递的变量

    def arg_filter(**kw):
        return dict((k,v) for k,v in kw.items() if v not in (None, ''))
    
    foo(**arg_filter(a=1,b=None,c=''))
    
        5
  •  1
  •   Jon Clements    11 年前

    未经充分测试,但应作为基础:

    import inspect
    from functools import wraps
    
    def force_default(f):
        @wraps(f)
        def func(*args, **kwargs):
            ca = inspect.getcallargs(f, *args, **kwargs)
            da = inspect.getargspec(f)
            dv = dict(zip(reversed(da.args), reversed(da.defaults)))
            for k, v in ca.iteritems():
                if v is None or v == '':
                    ca[k] = dv[k]
            return f(**ca)
        return func
    
    @force_default
    def foo(a, b=1, c=2, d=3):
        print a, b, c, d
    
    foo(6, '', None, 'rabbit!')
    # 6 1 2 rabbit!