可选参数,要求某些组合必填
我有一个一般性的问题,还有一个具体的使用场景。
可选参数其实挺简单的,比如你可以这样写:def func(a, b, c=None): ...
。然后在函数内部用到c的地方,先写个if c:
来判断一下,或者类似的做法。但是如果有些参数组合是必须的,那该怎么处理呢?一般来说,我们需要考虑各种情况,比如某些参数存在而某些参数不存在。比如对于一个函数def func(a, b, c=None, d=None, e=None, f=None): ...
,可能会出现一些奇怪的要求:提供c和d,但不提供e和f,或者只提供e,或者至少提供c、d、e和f中的三个。但我的使用场景并不需要这么复杂。
对于def func(a, b, c=None, d=None): ...
,我想要的情况是:c和d中必须提供其中一个,不能两个都不提供,也不能两个都提供。
我想到的解决方案包括:
- 在函数内部手动检查c和d有多少个不是None,如果不是正好1个,就返回一个错误,提示必须指定一个。
例如:
def func(a, b, c=None, d=None):
how_many_provided = len([arg for arg in [c, d] if arg]) # count the non-None optional args
if not how_many_provided == 1:
return "Hey, provide exactly 1 of 'c' and 'd'"
if c:
# stuff to do if c is provided
elif d:
# stuff to do if d is provided
- 另一个方法是把函数改成def func(a, b, e, f): ...
,其中e代表c或d,而f则指示e代表的是哪个。
例如:
def func(a, b, e, f):
if f == 'c':
# stuff to do if c is provided, with e as c
if f == 'd':
# stuff to do if d is provided, with e as d
这些方法都可以,但有什么标准的、被广泛接受的、符合Python风格的做法呢?
3 个回答
这里还有一个例子,它允许你指定参数,并且区分了 c=None
和 c
没有给出这两种情况,同时还明确提供了参数名称:
undefined = object()
def func(a, b, c=undefined, d=undefined):
if (c is undefined) ^ (d is undefined):
raise TypeError("Hey, provide exactly 1 of 'c' and 'd'")
...
在 Python 3 中,只有关键字的参数让这一切变得更简单,确保调用者明确指定 c
或 d
:
def func(a, b, *, c=undefined, d=undefined):
if (c is undefined) ^ (d is undefined):
raise TypeError("Hey, provide exactly 1 of 'c' and 'd'")
你可以直接使用关键字参数字典:
def func(a, b, **kwargs):
valid_args = len(kwargs) == 1 and ('c' in kwargs or 'd' in kwargs)
if not valid_args:
return "Hey, provide exactly 1 of 'c' and 'd'"
if 'c' in kwargs:
# stuff to do if c is provided
elif 'd' in kwargs:
# stuff to do if d is provided
我觉得在你这个简单的例子中,最简单的方法就是把代码拆分成几个不同的函数。每个函数负责不同的工作,就像你最后提到的那种情况。
def funcC(a, b, c):
# stuff to do if c is provided, with e as c
common_func(a,b,c, None)
def funcD(a, b, d):
# stuff to do if d is provided, with e as d
common_func(a,b,None, d)
这样一来,用户就能清楚哪些参数是重要的,而且只能使用有效的组合,用户不需要猜测,也不会有调用错误的机会。作为提供函数的人,你可以为那些用户没有提供的参数准备好所需的内容。
如果你想了解更多相关的内容,可以在网上搜索“标志参数”,比如看看 Martin Fowler 和 Stack Overflow 上的讨论。这些讨论通常提到布尔参数,但实际上它们的意思是根据某个参数走不同的代码路径,而这个参数本身没有其他影响。
另一个可以查找的词是“控制耦合”。