检查python

时间:2016-05-03 10:13:58

标签: python

我需要一些关于如何在python中实现显式检查无效输入的最佳(以及在多大程度上)的建议。来自具有强类型设置的C ++背景,这一直让我感到困惑。

因此,为了讨论,让我们假设我们有以下方法签名:

def m(start:float, up:float, down:float):
    pass

现在start应该大于或等于0而其他两个应该大于0.我可以做类似的事情:

def m(start:float, up:float=1, down:float=1):
    if start <= 0.0:
        raise ValueError("Error")
    if up< 0.0:
        raise ValueError("Error")
    if down< 0.0:
        raise ValueError("Error")

我猜这个很好只要输入类型是float或某个与float相当的数字类型。但是在python中没有什么能阻止用户调用函数:

m(start=[], up="Hello", down={})

在这种情况下,所有这些比较都将毫无意义。处理这种情况的pythonic方法是什么?

3 个答案:

答案 0 :(得分:0)

您可以使用type()检查参数是否为浮点数 例如if type(start) != float
或者您可以使用isinstance()函数:

if not isinstance(start, float):
    raise TypeError

答案 1 :(得分:0)

有几种方法,最常见的可能是:EAFP(比容许更容易要求原谅):

def m(start:float, up:float=1, down:float=1):
    try:
        if start <= 0.0:
            raise ValueError
        if up < 0.0:
            raise ValueError
        if down < 0.0:
            raise ValueError
    except TypeError:
        # This is just to give a more meaningful error message.
        raise TypeError('Arguments must be numbers.')

这对于python 2会无声地失败,但是在python 3中,当将not-number与数字进行比较时会引发TypeError。从这个意义上来说,这会让他意识到自己做错了什么。

另一种选择是类型检查和LBYL的概念(在你跳跃之前看)也称为防御性编程

from numbers import Real # or Number if you want to allow compley-types too

def m(start, up=1, down=1):
    # Compare if each argument is a real (floating point) number:
    if not isinstance(start, Real) or not isinstance(up, Real) or not isinstance(down, Real) :
        raise TypeError("Arguments must be numbers.")
    ...

大多数人(包括我自己)都认为EAFP与try ... except ...更加pythonic但如果你对isinstance感觉更舒服 - 那么这些提供了另一种选择。

答案 2 :(得分:0)

在回答您的问题时:m(start=[], up="Hello", down={})会在尝试if start <= 0.0:后立即崩溃您的程序(引发异常)。如果您有m('3', '4', '55.27'),情况可能会更成问题,因为这些字符串转换为float。

如果您希望在任何到达的非float或not数字表示调用代码中的逻辑错误的情况下都是防御性的,那么您可以在运行时进行测试。 assert语句会引发一个不太可能被不恰当地捕获的AssertionError。所以:

assert type(start)==float, "start is not a float"
assert type(up)  ==float or type(up)  ==int
assert type(down)==float or type(down)==int

这些还具有以下优点:它们很容易在以后注释掉,并且如果它们紧跟def语句后立即读(注释或不注释),就像其他语言中的声明一样。

您还可以使用assert:

检查值
assert  start >= 0
assert up > 0 and down > 0

或者最好提升ValueError因为这些是价值错误:

if start < 0 or up <= 0 or down <= 0:
     raise ValueError("Bad arguments start={} up={} down={}".format(start,up,down) )

主要区别在于提升ValueError旨在表示可能被调用者明显捕获的信号,而assert旨在表示已检测到逻辑错误并且立即终止程序可能是最好的。 (或者,传播到最顶端的catch-all处理程序,比如交互式命令解析器。没有硬分界线。)