我应该在Python中对错误/非法参数组合提出哪个异常?

我想知道在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,或者有另一种首选方法?

374973 次浏览

我刚刚看到在这种情况下使用的内置ValueError

我将继承ValueError

class IllegalArgumentError(ValueError):
pass

有时创建自己的异常更好,但从内置异常继承,这尽可能接近您想要的。

如果您需要捕获该特定错误,则有一个名称很有帮助。

我不确定我是否同意从ValueError继承-我对留档的解释是ValueError只有应该由内置程序提出……从它继承或自己提出似乎是不正确的。

当内置操作或 函数接收一个参数,该参数具有 正确的类型,但不合适 值,而情况不是 用一个更精确的例外来描述 例如IndexError。

--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真的没有意义-您的自定义类在使用上与属性值错误相同,那么为什么不使用它呢?

同意Markus的建议滚动自己的异常,但异常的文本应该澄清问题出在参数列表中,而不是单个参数值。我建议:

class BadCallError(ValueError):
pass

当缺少特定调用所需的关键字参数时使用,或者参数值单独有效但彼此不一致时使用。当特定参数类型正确但超出范围时,ValueError仍然是正确的。

这不应该是Python中的标准异常吗?

一般来说,我希望Python风格在区分函数的错误输入(调用者的错误)和函数内的错误结果(我的错误)方面更加清晰。所以也可能有一个BadArgumentError来区分参数中的值错误和局部值错误。

我认为处理这个问题的最好方法是python本身处理它的方式。Python引发了一个TypeError。例如:

$ 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异常错误参数”时发现了这个页面,我很惊讶(对我来说)这个明显的答案在这个问题被问到后的十年里从未被提出过。

这取决于争论的问题是什么。

如果参数的类型错误,则引发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值的递归意味着一个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(完整的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)

P. S.有关python内置异常的列表,请转到此处: https://docs.python.org/3/library/exceptions.html(这是官方的python数据库)