简体   繁体   English

对于 Python 中的错误/非法参数组合,我应该引发哪个异常?

[英]Which exception should I raise on bad/illegal argument combinations in Python?

I was wondering about the best practices for indicating invalid argument combinations in Python.我想知道在 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 .唯一的烦恼是每个包都有自己的,通常略有不同的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?我知道在 Java 中存在java.lang.IllegalArgumentException - 是否很好理解每个人都会在 Python 中创建自己的BadValueError或者是否有另一种首选方法?

I would just raise ValueError , unless you need a more specific exception..我只会提高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")

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?class BadValueError(ValueError):pass真的没有意义——你的自定义类在使用上与ValueError相同,那么为什么不使用它呢?

I would inherit from ValueError我会从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.如果您需要捕获该特定错误,拥有一个名称会很有帮助。

I think the best way to handle this is the way python itself handles it.我认为处理这个问题的最好方法是 python 本身处理它的方式。 Python raises a TypeError. Python 引发了一个 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.我们的初级开发人员刚刚在谷歌搜索“python 异常错误参数”中找到了这个页面,我很惊讶自问这个问题以来的十年里,没有人提出明显的(对我来说)答案。

It depends on what the problem with the arguments is.这取决于参数的问题是什么。

If the argument has the wrong type, raise a TypeError.如果参数的类型错误,则引发 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.但是请注意,在 Python 中我们很少进行这样的检查。 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.如果我们只检查布尔值,也许某些代码用户稍后会向它提供一个字符串,因为知道非空字符串始终为 True。 It might save him a cast.这可能会为他节省一个演员。

If the arguments have invalid values, raise ValueError.如果参数具有无效值,则引发 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

我主要只是看到在这种情况下使用的内置ValueError

You would most likely use ValueError ( raise ValueError() in full) in this case, but it depends on the type of bad value.在这种情况下,您很可能会使用ValueErrorraise ValueError() in full),但这取决于错误值的类型。 For example, if you made a function that only allows strings, and the user put in an integer instead, you would you TypeError instead.例如,如果您创建了一个只允许字符串的函数,而用户输入的是一个整数,那么您将使用TypeError If a user inputted a wrong input (meaning it has the right type but it does not qualify certain conditions) a Value Error would be your best choice.如果用户输入了错误的输入(意味着它具有正确的类型但不符合某些条件),则Value Error将是您的最佳选择。 Value Error can also be used to block the program from other exceptions, for example, you could use a ValueError to stop the shell form raising a ZeroDivisionError , for example, in this function: Value Error 也可用于阻止程序发生其他异常,例如,您可以使用ValueError来阻止 shell 表单引发ZeroDivisionError ,例如,在此函数中:

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 For a list of python built-in exceptions, go here: https://docs.python.org/3/library/exceptions.html (This is the official python databank) PS 有关 python 内置异常的列表,请转到此处: https : //docs.python.org/3/library/exceptions.html (这是官方 python 数据库)

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.我不确定我是否同意从ValueError继承——我对文档的解释是ValueError应该由内置函数引发……从它继承或自己引发似乎不正确。

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.当内置操作或函数接收到类型正确但值不合适的参数时引发,并且这种情况没有用更精确的异常(如 IndexError)描述。

-- ValueError documentation -- ValueError 文档

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.同意 Markus 的建议,推出您自己的例外,但例外的文本应阐明问题出在参数列表中,而不是单个参数值中。 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.当特定参数是正确类型但超出范围时, ValueError仍然是正确的。

Shouldn't this be a standard exception in Python?这不应该是 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).一般来说,我希望 Python 风格在区分函数的错误输入(调用者的错误)和函数中的错误结果(我的错误)方面更加清晰。 So there might also be a BadArgumentError to distinguish value errors in arguments from value errors in locals.所以也可能有一个 BadArgumentError 来区分参数中的值错误和局部变量中的值错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM