我想知道在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,这是很好理解的,还是有其他的首选方法?


当前回答

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

如果实参的类型错误,则引发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")

或者在这个特定的情况下,使用recurse的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继承

class IllegalArgumentError(ValueError):
    pass

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

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

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

如果实参的类型错误,则引发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")

或者在这个特定的情况下,使用recurse的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。

You would most likely use ValueError (raise ValueError() in full) in this case, but it depends on the type of bad value. For example, if you made a function that only allows strings, and the user put in an integer instead, you would you TypeError instead. 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 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:

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)

附注:python内置异常列表,请点击此处: https://docs.python.org/3/library/exceptions.html(这是官方的python数据库)

我只会引发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")

真的没有必要做类BadValueError(ValueError):pass -你的自定义类在使用ValueError时是相同的,所以为什么不使用它呢?