我需要一些关于如何在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方法是什么?
答案 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处理程序,比如交互式命令解析器。没有硬分界线。)