如何在 Python 中对变量进行类型检查?
-
19-08-2019 - |
题
我有一个 Python 函数,它接受一个数字参数 必须 是一个整数才能正确运行。在 Python 中验证这一点的首选方法是什么?
我的第一反应是做这样的事情:
def isInteger(n):
return int(n) == n
但我不禁想到,这 1)昂贵 2)丑陋 3)受到机器 epsilon 的温柔怜悯。
Python 是否提供任何类型检查变量的本机方法?或者这是否被认为违反了语言的动态类型设计?
编辑:因为很多人都问过 - 有问题的应用程序使用 IPv4 前缀,从平面文本文件中获取数据。如果任何输入被解析为浮点数,则该记录应被视为格式错误并被忽略。
解决方案
isinstance(n, int)
如果你需要知道它是否肯定是一个实际的INT而不是为int的子类(一般情况下不应需要这样做):
type(n) is int
这样:
return int(n) == n
不是一个好主意,如十字型的比较可以是真实的 - 特别是int(3.0)==3.0
其他提示
对,如埃文说,不键入检查。只要尝试使用值:
def myintfunction(value):
""" Please pass an integer """
return 2 + value
不具有一个类型检测。这是好多了!让我们看看会发生什么,当我尝试:
>>> myintfunction(5)
7
这工作,因为它是一个整数。嗯。让我们试着一些文本。
>>> myintfunction('text')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in myintfunction
TypeError: unsupported operand type(s) for +: 'int' and 'str'
这显示了一个错误,类型错误,这是它应该做的反正。如果调用者想要赶上,这是可能的。
您会怎么做,如果你做一个类型检测?显示一个错误吗?所以,你不必进行类型检查,因为这个错误已经自动显示出来。
此外,因为你没有进行类型检查,你有你的功能与其他类型的工作:
浮标:
>>> print myintfunction(2.2)
4.2
复数:
>>> print myintfunction(5j)
(2+5j)
小数:
>>> import decimal
>>> myintfunction(decimal.Decimal('15'))
Decimal("17")
即使是号码添加完全是随意的对象!
>>> class MyAdderClass(object):
... def __radd__(self, value):
... print 'got some value: ', value
... return 25
...
>>> m = MyAdderClass()
>>> print myintfunction(m)
got some value: 2
25
所以,你清楚地得到通过类型检查什么。而失去了很多东西。
更新:
既然你编辑的问题,这是现在很清楚,你的应用程序调用一些例行的上游有意义只能用整数。
既然如此,我仍然认为你应该传递参数的所接收以上游功能。上游函数将处理它正确地例如提高一个错误,如果它需要。我强烈的怀疑您的函数,处理与IP地址的行为很奇怪,如果你传递一个浮动。如果你可以给我们的库的名称,我们可以检查你。
但是...如果上游职能将行为不正确,如果你传递一个浮动杀死一些孩子(我还是很怀疑),那么就只需调用它int()
:
def myintfunction(value):
""" Please pass an integer """
return upstreamfunction(int(value))
你还没有类型检查,所以你得到不类型检查的最大利益。
如果即使在所有这一切,你真正想要的,输入检查,尽管它减少了应用程序的可读性和性能绝对没有好处,使用assert
做到这一点。
assert isinstance(...)
assert type() is xxxx
这样,我们可以关闭assert
s和删除此<sarcasm>
特征通过调用它作为
</sarcasm>
python -OO program.py
if type(n) is int
此检查是否n
是一个Python int和仅一个int。它不会接受int
的子类。
类型检查,但是,不符合“Python的方式”。你最好使用n
为int,如果它抛出一个异常,捕获它和行动上面。
Python 现在支持 逐渐打字 通过 打字模块 和 米皮. 。这 typing
从 Python 3.5 开始,模块是 stdlib 的一部分,可以下载 来自 PyPi 如果您需要 Python 2 或以前版本的 Python 3 的向后移植。您可以安装 mypy
通过跑步 pip install mypy
从命令行。
简而言之,如果您想验证某个函数是否接受 int、float 并返回字符串,您可以像这样注释您的函数:
def foo(param1: int, param2: float) -> str:
return "testing {0} {1}".format(param1, param2)
如果你的文件被命名为 test.py
, ,一旦安装了 mypy,你就可以通过运行进行类型检查 mypy test.py
从命令行。
如果您使用的是不支持函数注释的旧版本 Python,则可以使用类型注释来实现相同的效果:
def foo(param1, param2):
# type: (int, float) -> str
return "testing {0} {1}".format(param1, param2)
您使用相同的命令 mypy test.py
对于 Python 3 文件,以及 mypy --py2 test.py
对于 Python 2 文件。
Python 解释器在运行时完全忽略类型注释,因此它们会产生最小甚至没有开销——通常的工作流程是处理代码并定期运行 mypy 以捕获错误和错误。某些 IDE(例如 PyCharm)可以理解类型提示,并可以在您直接编辑时提醒您代码中的问题和类型不匹配。
如果出于某种原因,您需要在运行时检查类型(也许您需要验证大量输入?),您应该遵循其他答案中列出的建议 - 例如使用 isinstance
, issubclass
, ,等等。还有一些库,例如 执行 尝试在运行时执行类型检查(尊重您的类型注释),尽管我不确定它们在撰写本文时的生产准备情况如何。
有关更多信息和详细信息,请参阅 我的网站, , 这 mypy 常见问题解答, , 和 公众号 484.
不要键入检查。鸭打字的整点是,你不应该。举例来说,如果有什么有人做这样的事情:
class MyInt(int):
# ... extra stuff ...
在Python编程和执行类型检查,你可能会在其他语言似乎就像选择螺丝刀与一鼓作气钉子。这是更优雅的使用Python的异常处理功能。
从一个交互式命令行,则可以运行就像一个语句:
int('sometext')
这将产生错误 - IPython的告诉我:
<type 'exceptions.ValueError'>: invalid literal for int() with base 10: 'sometext'
现在你可以编写一些代码:
try:
int(myvar) + 50
except ValueError:
print "Not a number"
这是可以自定义为所需的任何行动,并赶上预期的任何错误。它看起来有点令人费解,但适合在非常可读的代码的语法和Python和结果的成语(一旦你习惯了讲的Python)。
我会被引诱到这样的:
def check_and_convert(x):
x = int(x)
assert 0 <= x <= 255, "must be between 0 and 255 (inclusive)"
return x
class IPv4(object):
"""IPv4 CIDR prefixes is A.B.C.D/E where A-D are
integers in the range 0-255, and E is an int
in the range 0-32."""
def __init__(self, a, b, c, d, e=0):
self.a = check_and_convert(a)
self.b = check_and_convert(a)
self.c = check_and_convert(a)
self.d = check_and_convert(a)
assert 0 <= x <= 32, "must be between 0 and 32 (inclusive)"
self.e = int(e)
当你使用它什么都可以但你只能存储一个有效的整数传递的方式。
怎么样:
def ip(string):
subs = string.split('.')
if len(subs) != 4:
raise ValueError("incorrect input")
out = tuple(int(v) for v in subs if 0 <= int(v) <= 255)
if len(out) != 4:
raise ValueError("incorrect input")
return out
ofcourse有标准isinstance(3,INT)功能...