假设我有一个带有一些可选参数的方法。
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中我会跳转到一个工厂,但看起来这就是默认情况下应该避免的情况。
答案 0 :(得分: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”值视为默认值,这不仅意味着None
和''
,还意味着0
,False
,{{1}个人我会收紧界面并使用[]
并仅使用None
作为默认值。
None
答案 1 :(得分: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, ''}
,其含义略有不同(正如其他人所指出的那样)。
答案 2 :(得分: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
如果您希望捕获bool(v)
为False
的所有值v,则:
def foo(a, b, c, d):
b = b or 1
c = c or 2
d = d or 3
或者您可以使用另一个为您执行断言的函数来装饰该函数(根据您的使用情况,可能会或可能不会过度杀伤)
答案 3 :(得分: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=''))
答案 4 :(得分: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!