我想知道在 Python 中指示无效参数组合的最佳实践。我遇到过一些你有这样的功能的情况:
def import_to_orm(name, save=False, recurse=False):
"""
:param name: Name of some external entity to import.
:param save: Save the ORM object before returning.
:param recurse: Attempt to import associated objects as well. Because you
need the original object to have a key to relate to, save must be
`True` for recurse to be `True`.
:raise BadValueError: If `recurse and not save`.
:return: The ORM object.
"""
pass
唯一的烦恼是每个包都有自己的,通常略有不同BadValueError
。我知道在 Java 中存在 java.lang.IllegalArgumentException
- 是否每个人都将在 Python 中创建自己的 BadValueError
,或者是否有另一种首选方法?
我只会提出 ValueError,除非您需要更具体的例外..
def import_to_orm(name, save=False, recurse=False):
if recurse and not save:
raise ValueError("save must be True if recurse is True")
执行 class BadValueError(ValueError):pass
确实没有意义 - 您的自定义类在使用上与 ValueError 相同,那么为什么不使用它呢?
我会从 ValueError
继承
class IllegalArgumentError(ValueError):
pass
有时最好创建自己的异常,但从内置异常继承,它尽可能接近您想要的。
如果您需要捕获该特定错误,那么拥有一个名称会很有帮助。
我认为处理这个问题的最好方法是 python 本身处理它的方式。 Python 引发类型错误。例如:
$ python -c 'print(sum())'
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: sum expected at least 1 arguments, got 0
我们的初级开发人员刚刚在谷歌搜索“python 异常错误参数”中找到了这个页面,我很惊讶自从提出这个问题以来的十年里从未提出过明显的(对我而言)答案。
int('a')
)。 source
sum()
,即 TypeError
,但当参数类型正确时,OP 担心参数值的“非法”组合。在这种情况下,save
和 recurse
都是布尔值,但如果 recurse
是 True
,那么 save
不应该是 False
。这是一个ValueError
。我同意 TypeError
将回答对问题标题的某些解释,但不适用于所提供的示例。
这取决于论点的问题所在。
如果参数的类型错误,则引发 TypeError。例如,当您获得一个字符串而不是其中一个布尔值时。
if not isinstance(save, bool):
raise TypeError(f"Argument save must be of type bool, not {type(save)}")
但是请注意,在 Python 中我们很少进行这样的检查。如果参数真的无效,一些更深层次的函数可能会为我们抱怨。如果我们只检查布尔值,也许一些代码用户稍后会只给它一个字符串,知道非空字符串总是 True。这可能会为他节省一个演员。
如果参数具有无效值,则引发 ValueError。这似乎更适合您的情况:
if recurse and not save:
raise ValueError("If recurse is True, save should be True too")
或者在这种特定情况下,递归的 True 值意味着 Save 的 True 值。由于我认为这是从错误中恢复,因此您可能还想在日志中抱怨。
if recurse and not save:
logging.warning("Bad arguments in import_to_orm() - if recurse is True, so should save be")
save = True
我大多只是看到在这种情况下使用的内置 ValueError
。
在这种情况下,您很可能会使用 ValueError
(完整的 raise ValueError()
),但这取决于错误值的类型。例如,如果您创建了一个只允许字符串的函数,而用户输入了一个整数,那么您将改为 TypeError
。如果用户输入了错误的输入(意味着它具有正确的类型但不符合某些条件),Value Error
将是您的最佳选择。 Value
错误也可用于阻止程序出现其他异常,例如,您可以使用 ValueError
来停止引发 ZeroDivisionError
的 shell 表单,例如,在此函数中:
def function(number):
if not type(number) == int and not type(number) == float:
raise TypeError("number must be an integer or float")
if number == 5:
raise ValueError("number must not be 5")
else:
return 10/(5-number)
PS 对于 python 内置异常的列表,请到这里:https://docs.python.org/3/library/exceptions.html(这是官方 python 数据库)
同意 Markus 关于推出您自己的异常的建议,但异常的文本应阐明问题出在参数列表中,而不是单个参数值。我建议:
class BadCallError(ValueError):
pass
当缺少特定调用所需的关键字参数或参数值单独有效但彼此不一致时使用。当特定参数的类型正确但超出范围时,ValueError
仍然是正确的。
这不应该是 Python 中的标准例外吗?
一般来说,我希望 Python 风格能够更清晰地区分函数的错误输入(调用者的错误)和函数中的错误结果(我的错误)。所以可能还有一个 BadArgumentError 来区分参数中的值错误和本地值错误。
KeyError
(因为缺少的显式关键字在语义上与缺少该键的 **kwargs
字典相同)。
我不确定我是否同意从 ValueError
继承 - 我对文档的解释是,ValueError
仅应该由内置函数引发...从它继承或自己引发它似乎不正确。
当内置操作或函数接收到具有正确类型但值不适当的参数时引发,并且这种情况没有由更精确的异常(如 IndexError)描述。
ValueError
来完成这类事情,所以我认为你试图过多地阅读文档。
math.sqrt(-1)
,那么这是一个无论如何都需要修复的编程错误。ValueError
不打算在正常程序执行中被捕获,否则它会派生自RuntimeError
。ValueError
?