708

我想知道在 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 中创建自己的BadValueErrors 或者是否有另一种首选方法?

4

8 回答 8

785

我只会提出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相同,那么为什么不使用它呢?

于 2008-11-01T23:37:31.643 回答
127

我会继承自ValueError

class IllegalArgumentError(ValueError):
    pass

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

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

于 2008-11-01T23:17:49.250 回答
40

我认为处理这个问题的最好方法是 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 异常错误参数”中找到了这个页面,我很惊讶自从提出这个问题以来的十年里从未提出过明显的(对我而言)答案。

于 2018-08-01T16:17:55.077 回答
28

这取决于论点的问题所在。

如果参数的类型错误,则引发 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
于 2019-06-25T08:47:13.453 回答
14

我大多只是看到ValueError在这种情况下使用的内置函数。

于 2008-11-01T23:17:40.717 回答
2

在这种情况下,您很可能会使用ValueError( raise ValueError()in full) ,但这取决于错误值的类型。例如,如果您创建了一个只允许字符串的函数,而用户输入了一个整数,那么您会TypeError改为。如果用户输入了错误的输入(意味着它具有正确的类型但不符合某些条件)aValue Error将是您的最佳选择。ValueError 也可用于阻止程序发生其他异常,例如,您可以使用 aValueError来停止引发 a 的 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 对于 python 内置异常的列表,请访问这里: https ://docs.python.org/3/library/exceptions.html (这是官方 python 数据库)

于 2021-08-11T18:20:58.567 回答
-1

我不确定我是否同意继承ValueError——我对文档的解释是,ValueError它只应该由内置函数提出……从它继承或自己提出似乎不正确。

当内置操作或函数接收到具有正确类型但值不适当的参数时引发,并且这种情况没有由更精确的异常(如 IndexError)描述。

-- ValueError 文档

于 2008-11-01T23:21:54.920 回答
-1

同意 Markus 的建议来推出您自己的异常,但异常的文本应阐明问题出在参数列表中,而不是单个参数值。我建议:

class BadCallError(ValueError):
    pass

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

这不应该是 Python 中的标准例外吗?

一般来说,我希望 Python 风格能够更清晰地区分函数的错误输入(调用者的错误)和函数中的错误结果(我的错误)。所以可能还有一个 BadArgumentError 来区分参数中的值错误和本地值错误。

于 2017-10-05T15:20:13.323 回答