Let's say I have a method with a few optional parameters.
假设我有一个带有一些可选参数的方法。
def foo(a, b=1, c=2, d=3)
def foo(a,b = 1,c = 2,d = 3)
How do I go about calling it so that if my variables are None or empty strings the defaults are used?
如何调用它以便如果我的变量为None或空字符串,则使用默认值?
Conditionals like the following seems like a horrible solution:
像下面这样的条件似乎是一个可怕的解决方案:
if b and not c and d:
foo(myA, b = myB, d = myD)
elif b and not c and not d:
...
In Java I'd jump for a factory, but it seems like that's what defaults are supposed to avoid in this case.
在Java中,我会跳转到一个工厂,但看起来这就是默认情况下应该避免的情况。
5 个解决方案
#1
7
I would change foo
so it replaces empty values with default ones.
我会改变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
Note that this will treat all "false-y" values as defaults, meaning not only None
and ''
but also 0
, False
, []
, etc. Personally I would tighten the interface up and use None
and only None
as a default value.
请注意,这会将所有“false-y”值视为默认值,不仅意味着None和'',还包括0,False,[]等。我个人会收紧界面并使用None,只有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
#2
3
Though I agree that changing the method is a better idea, here's an alternative that changes the calling part by using a dict
of arguments, which is filtered and then unpacked:
虽然我同意更改方法是一个更好的主意,但这里有一个替代方法,通过使用参数的dict来更改调用部分,该参数将被过滤然后解压缩:
d = {'b': myB, 'd': myD}
foo(myA, **{k: d[k] for k in d if d[k]})
Of course if d[k]
can be replaced by if d[k] not in {None, ''}
for example, which has a slightly different meaning (as pointed out by others).
当然,如果d [k]可以被替换为if d [k]而不是{None,''},例如,其具有略微不同的含义(如其他人所指出的)。
#3
2
If you want to catch ONLY None
and ''
:
如果你想只捕获无和'':
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
If you want to catch all values v such that bool(v)
is False
, then:
如果你想捕获所有值v使得bool(v)为False,那么:
def foo(a, b, c, d):
b = b or 1
c = c or 2
d = d or 3
Or you could decorate the function with another function that does the assertions for you (which may or may not be overkill, based on your use case)
或者您可以使用另一个为您执行断言的函数来装饰该函数(根据您的用例,这可能是也可能不是过度杀伤)
#4
2
You could call a function that filters out the variables you don't want passed down
您可以调用一个函数来过滤掉您不想传递的变量
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
Not fully tested, but should act as a base:
没有经过充分测试,但应作为基础:
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!
#1
7
I would change foo
so it replaces empty values with default ones.
我会改变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
Note that this will treat all "false-y" values as defaults, meaning not only None
and ''
but also 0
, False
, []
, etc. Personally I would tighten the interface up and use None
and only None
as a default value.
请注意,这会将所有“false-y”值视为默认值,不仅意味着None和'',还包括0,False,[]等。我个人会收紧界面并使用None,只有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
#2
3
Though I agree that changing the method is a better idea, here's an alternative that changes the calling part by using a dict
of arguments, which is filtered and then unpacked:
虽然我同意更改方法是一个更好的主意,但这里有一个替代方法,通过使用参数的dict来更改调用部分,该参数将被过滤然后解压缩:
d = {'b': myB, 'd': myD}
foo(myA, **{k: d[k] for k in d if d[k]})
Of course if d[k]
can be replaced by if d[k] not in {None, ''}
for example, which has a slightly different meaning (as pointed out by others).
当然,如果d [k]可以被替换为if d [k]而不是{None,''},例如,其具有略微不同的含义(如其他人所指出的)。
#3
2
If you want to catch ONLY None
and ''
:
如果你想只捕获无和'':
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
If you want to catch all values v such that bool(v)
is False
, then:
如果你想捕获所有值v使得bool(v)为False,那么:
def foo(a, b, c, d):
b = b or 1
c = c or 2
d = d or 3
Or you could decorate the function with another function that does the assertions for you (which may or may not be overkill, based on your use case)
或者您可以使用另一个为您执行断言的函数来装饰该函数(根据您的用例,这可能是也可能不是过度杀伤)
#4
2
You could call a function that filters out the variables you don't want passed down
您可以调用一个函数来过滤掉您不想传递的变量
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
Not fully tested, but should act as a base:
没有经过充分测试,但应作为基础:
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!