问题:我应该针对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
-是否众所周知每个人都将BadValueError
在Python中创建自己的s还是存在另一种首选方法?
I was wondering about the best practices for indicating invalid argument combinations in Python. I’ve come across a few situations where you have a function like so:
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
The only annoyance with this is that every package has its own, usually slightly differing BadValueError
. I know that in Java there exists java.lang.IllegalArgumentException
— is it well understood that everybody will be creating their own BadValueError
s in Python or is there another, preferred method?
回答 0
我只会提出ValueError,除非您需要更具体的exceptions。
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相同,那么为什么不使用它呢?
I would just raise ValueError, unless you need a more specific exception..
def import_to_orm(name, save=False, recurse=False):
if recurse and not save:
raise ValueError("save must be True if recurse is True")
There’s really no point in doing class BadValueError(ValueError):pass
– your custom class is identical in use to ValueError, so why not use that?
回答 1
我会继承 ValueError
class IllegalArgumentError(ValueError):
pass
有时最好创建自己的异常,但要从内置异常中继承,该异常应尽可能接近您想要的异常。
如果需要捕获该特定错误,请使用一个名称。
I would inherit from ValueError
class IllegalArgumentError(ValueError):
pass
It is sometimes better to create your own exceptions, but inherit from a built-in one, which is as close to what you want as possible.
If you need to catch that specific error, it is helpful to have a name.
回答 2
我认为处理此问题的最佳方法是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
我们的初级开发人员刚刚在Google搜索“ python异常错误参数”中找到了此页面,而令我惊讶的是,自问这个问题以来,十年来从未出现过明显的(对我而言)答案。
I think the best way to handle this is the way python itself handles it. Python raises a TypeError. For example:
$ python -c 'print(sum())'
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: sum expected at least 1 arguments, got 0
Our junior dev just found this page in a google search for “python exception wrong arguments” and I’m surprised that the obvious (to me) answer wasn’t ever suggested in the decade since this question was asked.
回答 3
我几乎只看到ValueError
过这种情况下使用的内建函数。
I’ve mostly just seen the builtin ValueError
used in this situation.
回答 4
这取决于参数的问题。
如果参数的类型错误,则引发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
It depends on what the problem with the arguments is.
If the argument has the wrong type, raise a TypeError. For example, when you get a string instead of one of those Booleans.
if not isinstance(save, bool):
raise TypeError(f"Argument save must be of type bool, not {type(save)}")
Note, however, that in Python we rarely make any checks like this. If the argument really is invalid, some deeper function will probably do the complaining for us. And if we only check the boolean value, perhaps some code user will later just feed it a string knowing that non-empty strings are always True. It might save him a cast.
If the arguments have invalid values, raise ValueError. This seems more appropriate in your case:
if recurse and not save:
raise ValueError("If recurse is True, save should be True too")
Or in this specific case, have a True value of recurse imply a True value of save. Since I would consider this a recovery from an error, you might also want to complain in the log.
if recurse and not save:
logging.warning("Bad arguments in import_to_orm() - if recurse is True, so should save be")
save = True
回答 5
我不确定我是否同意继承ValueError
-我对文档的解释ValueError
是仅应由内建函数引发…从中继承或自己引发它似乎不正确。
当内置操作或函数接收到类型正确但值不合适的参数时引发,并且这种情况没有通过诸如IndexError之类的更精确的异常描述。
– ValueError异常文档
I’m not sure I agree with inheritance from ValueError
— my interpretation of the documentation is that ValueError
is only supposed to be raised by builtins… inheriting from it or raising it yourself seems incorrect.
Raised when a built-in operation or
function receives an argument that has
the right type but an inappropriate
value, and the situation is not
described by a more precise exception
such as IndexError.
— ValueError documentation
回答 6
同意Markus关于提出自己的异常的建议,但是该异常的文字应阐明问题出在参数列表中,而不是单个参数值中。我建议:
class BadCallError(ValueError):
pass
当缺少特定调用所需的关键字参数或参数值分别有效但彼此不一致时使用。 ValueError
当特定参数是正确类型但超出范围时,仍将是正确的。
这不是Python中的标准exceptions吗?
总的来说,我希望Python样式在区分函数的错误输入(调用者的错误)和函数内部的错误结果(我的错误)方面更加犀利。因此,可能还存在BadArgumentError来区分参数中的值错误和本地变量中的值错误。
Agree with Markus’ suggestion to roll your own exception, but the text of the exception should clarify that the problem is in the argument list, not the individual argument values. I’d propose:
class BadCallError(ValueError):
pass
Used when keyword arguments are missing that were required for the specific call, or argument values are individually valid but inconsistent with each other. ValueError
would still be right when a specific argument is right type but out of range.
Shouldn’t this be a standard exception in Python?
In general, I’d like Python style to be a bit sharper in distinguishing bad inputs to a function (caller’s fault) from bad results within the function (my fault). So there might also be a BadArgumentError to distinguish value errors in arguments from value errors in locals.