3

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

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 中,我会选择一个工厂,但在这种情况下,这似乎是默认值应该避免的。

4

5 回答 5

7

我会改变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”值视为默认值,不仅意味着Noneand ,''而且0, False,[]等。我个人会收紧界面并使用Noneand 仅None作为默认值。

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
于 2013-08-26T21:49:51.347 回答
3

虽然我同意更改方法是一个更好的主意,但这里有一个替代方法,它通过使用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, ''}为例如,其含义略有不同(正如其他人所指出的那样)。

于 2013-08-26T22:00:33.000 回答
2

如果您只想捕获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

或者您可以使用另一个为您执行断言的函数来装饰该函数(根据您的用例,这可能会也可能不会过分杀伤力)

于 2013-08-26T21:50:21.507 回答
2

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

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=''))
于 2013-08-26T22:02:20.470 回答
1

未经过全面测试,但应作为基础:

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!
于 2013-08-26T22:27:22.317 回答