Call function without optional arguments if they are None
although ** is definitely a language feature, it's surely not created for solving this particular problem. Your suggestion works, so does mine. Which one works better depends on the rest of the OP's code. However, there is still no way to write
f(x or dont_pass_it_at_all)
- blue_note
Thanks to your great answers, I thought I'd try to do just that:
# gen.py
def callWithNonNoneArgs(f, *args, **kwargs):
kwargsNotNone = {k: v for k, v in kwargs.items() if v is not None}
return f(*args, **kwargsNotNone)
# python interpreter
>>> import gen
>>> def alpha(p1="foo", p2="bar"):
... print('{0},{1}'.format(p1,p2))
...
>>> gen.callWithNonNoneArgs(alpha, p1="FOO", p2=None)
FOO,bar
>>> def beta(ree, p1="foo", p2="bar"):
... print('{0},{1},{2}'.format(ree,p1,p2))
...
>>> beta('hello', p2="world")
hello,foo,world
>>> beta('hello', p2=None)
hello,foo,None
>>> gen.callWithNonNoneArgs(beta, 'hello', p2=None)
hello,foo,bar
This is probably not perfect, but it seems to work: It's a function that you can call with another function and it's arguments, and it applies deceze's answer to filter out the arguments that are None
.
But assume that alpha is used in other places where it is actually supposed to handle None as it does.
To respond to this concern, I have been known to have a None
-like value which isn't actually None
for this exact purpose.
_novalue = object()
def alpha(p1=_novalue, p2=_novalue):
if p1 is _novalue:
p1 = "foo"
if p2 is _novalue:
p2 = "bar"
print('{0},{1}'.format(p1, p2))
Now the arguments are still optional, so you can neglect to pass either of them. And the function handles None
correctly. If you ever want to explicitly not pass an argument, you can pass _novalue
.
>>> alpha(p1="FOO", p2=None)
FOO,None
>>> alpha(p1="FOO")
FOO,bar
>>> alpha(p1="FOO", p2=_novalue)
FOO,bar
and since _novalue
is a special made-up value created for this express purpose, anyone who passes _novalue
is certainly intending the "default argument" behavior, as opposed to someone who passes None
who might intend that the value be interpreted as literal None
.
Pass the arguments as kwargs from a dictionary, from which you filter out the None
values:
kwargs = dict(p1='FOO', p2=None)
alpha(**{k: v for k, v in kwargs.items() if v is not None})