问题
What is the best practice in python to check if at least one of the default parameters of the function is specified?
Let's suppose we have some function:
def some_function(arg_a=None, arg_b=None, arg_c=False)
with some default parameters. In my case, I need to check if either arg_a
or arg_b
is specified. So I thought of implementing something like this:
def some_function(arg_a=None, arg_b=None, arg_c=False):
...
if arg_a is not None:
...
elif arg_b is not None:
...
else:
raise ValueError('Expected either arg_a or arg_b args')
...
...
So, what is more pythonic way to implement such kind of functionality?
回答1:
You could use all
to check if they all equal None
and raise the ValueError
:
if all(v is None for v in {arg_a, arg_b}):
raise ValueError('Expected either arg_a or arg_b args')
this gets rid of those if-elif
clauses and groups all checks in the same place:
f(arg_a=0) # ok
f(arg_b=0) # ok
f() # Value Error
Alternatively, with any()
:
if not any(v is not None for v in {arg_a, arg_b}):
raise ValueError('Expected either arg_a or arg_b args')
but this is definitely more obfuscated.
In the end, it really depends on what the interpretation of pythonic actually is.
回答2:
Depends on what you expect as values for arg_a
and arg_b
, but this is generally sufficient.
if not arg_a and not arg_b:
raise ValueError(...)
Assumes that arg_a
and arg_b
are not both booleans and cannot have zeros, empty strings/lists/tuples, etc. as parameters.
Depending on your needs, you can be more precise if you need to distinguish between None and 'falsies' such as False, 0, "", [], {}, (), etc.:
if arg_a is None and arg_b is None:
raise ValueError(...)
回答3:
You may consider using kwargs
if you have quite a number of such named arguments with mismatching default values:
def some_function(**kwargs):
reqd = ['arg_a', 'arg_b']
if not all(i in kwargs for i in reqd):
raise ValueError('Expected either {} args'.format(' or '.join(reqd)))
arg_a = kwargs.get('args_a')
arg_b = kwargs.get('args_b')
arg_c = kwargs.get('args_c', False)
回答4:
To check if at least one of the default parameters of the function specified
The solution using locals
, dict.values
and any
functions:
def some_function(arg_a=None, arg_b=None, arg_c=False):
args = locals()
if (any(args.values()) == True):
print('Ok')
else:
raise ValueError('At least one default param should be passed!')
some_function(False, 1) # Ok
some_function('text', False, None) # Ok
some_function(0, False, None) # Error
https://docs.python.org/2/library/functions.html#any
回答5:
Since you're proposing such a pattern, there's possibly some unifying meaning to arg_a
, arg_b
and arg_c
. If that's so, you could ...
from enum import Enum
class Group(Enum):
A = auto()
B = auto()
C = auto()
def some_function(val: int, t: Group):
if t == Group.A:
# do stuff with val
elif t == Group.B:
# do other stuff with val
elif t == Group.C:
# do other stuff with val
some_function(1, Group.A)
Here the caller is forced to specify both a value, and what the value corresponds to. This is tbh a bit of a hack around the lack of proper enumeration support in python and I've no idea if it's pythonic. It will however be picked up by a type checker.
来源:https://stackoverflow.com/questions/38881888/how-to-check-in-python-that-at-least-one-of-the-default-parameters-of-the-functi