我有一个 Python 函数,它接受一个数字参数,该参数必须是整数才能正确运行。 在 Python 中验证这一点的首选方法是什么?
我的第一反应是做这样的事情:
def isInteger(n):
return int(n) == n
但我忍不住想,这 1)昂贵 2)丑陋 3)受到机器 epsilon 的温柔怜悯。
Python 是否提供任何类型检查变量的本机方法? 或者这是否被认为违反了语言的动态类型设计?
编辑:由于很多人问过 - 有问题的应用程序使用 IPv4 前缀,从平面文本文件中获取数据。 如果任何输入被解析为浮点数,则该记录应被视为格式错误并被忽略。
I have a Python function that takes a numeric argument that must be an integer in order for it behave correctly. What is the preferred way of verifying this in Python?
My first reaction is to do something like this:
def isInteger(n):
return int(n) == n
But I can't help thinking that this is 1) expensive 2) ugly and 3) subject to the tender mercies of machine epsilon.
Does Python provide any native means of type checking variables? Or is this considered to be a violation of the language's dynamically typed design?
EDIT: since a number of people have asked - the application in question works with IPv4 prefixes, sourcing data from flat text files. If any input is parsed into a float, that record should be viewed as malformed and ignored.
发布评论
评论(9)
如果您需要知道它是否绝对是一个实际的 int 而不是 int 的子类(通常您不需要这样做):
this:
不是一个好主意,因为跨类型比较可以是正确的 - 特别是 <代码>int(3.0)==3.0
If you need to know whether it's definitely an actual int and not a subclass of int (generally you shouldn't need to do this):
this:
isn't such a good idea, as cross-type comparisons can be true - notably
int(3.0)==3.0
是的,正如埃文所说,不要输入检查。 只需尝试使用该值:
没有类型检查。 好多了! 让我们看看当我尝试它时会发生什么:
这有效,因为它是一个整数。 嗯。 让我们尝试一些文字。
它显示一个错误,TypeError,这是它应该做的。 如果调用者想要抓住这一点,这是可能的。
如果您进行类型检查,您会做什么? 显示错误吧? 因此您不必进行类型检查,因为错误已经自动显示。
另外,由于您没有进行类型检查,因此您的函数可以与其他类型一起使用:
浮点数:
复数:
小数:
甚至可以添加数字的完全任意对象!
所以通过类型检查你显然什么也得不到。 而且损失很多。
更新:
既然您已经编辑了问题,现在很明显您的应用程序调用了一些仅对整数有意义的上游例程。
既然如此,我仍然认为您应该将收到的参数传递给上游函数。 上游函数将正确处理它,例如,如果需要的话会引发错误。 我非常怀疑如果你传递一个浮点数,你处理IP的函数会表现得很奇怪。 如果您可以给我们图书馆的名称,我们可以为您检查。
但是......如果上游函数将表现不正确并杀死一些孩子,如果你向它传递一个浮点数(我仍然高度怀疑它),那么只需调用
int()
就可以了:你仍然不进行类型检查,因此您可以获得不进行类型检查的最大好处。
如果即使在所有这些之后,您确实想要进行类型检查,尽管它会降低应用程序的可读性和性能,但毫无好处,那么请使用
assert
来执行此操作。这样我们就可以关闭
assert
并从以下位置删除此
功能程序通过调用它作为
Yeah, as Evan said, don't type check. Just try to use the value:
That doesn't have a typecheck. It is much better! Let's see what happens when I try it:
That works, because it is an integer. Hm. Lets try some text.
It shows an error, TypeError, which is what it should do anyway. If caller wants to catch that, it is possible.
What would you do if you did a typecheck? Show an error right? So you don't have to typecheck because the error is already showing up automatically.
Plus since you didn't typecheck, you have your function working with other types:
Floats:
Complex numbers:
Decimals:
Even completely arbitrary objects that can add numbers!
So you clearly get nothing by typechecking. And lose a lot.
UPDATE:
Since you've edited the question, it is now clear that your application calls some upstream routine that makes sense only with ints.
That being the case, I still think you should pass the parameter as received to the upstream function. The upstream function will deal with it correctly e.g. raising an error if it needs to. I highly doubt that your function that deals with IPs will behave strangely if you pass it a float. If you can give us the name of the library we can check that for you.
But... If the upstream function will behave incorrectly and kill some kids if you pass it a float (I still highly doubt it), then just just call
int()
on it:You're still not typechecking, so you get most benefits of not typechecking.
If even after all that, you really want to type check, despite it reducing your application's readability and performance for absolutely no benefit, use an
assert
to do it.That way we can turn off
assert
s and remove this<sarcasm>
feature</sarcasm>
from the program by calling it asPython 现在支持通过 逐步输入。 org/3/library/typing.html" rel="nofollow noreferrer">打字模块 和 mypy。 从 Python 3.5 开始,
typing
模块是 stdlib 的一部分,可以下载 如果您需要 Python 2 或以前版本的 Python 3 的向后移植,请从 PyPi 获取。您可以通过从命令行运行pip install mypy
来安装mypy
。简而言之,如果您想验证某个函数是否接受 int、float 并返回字符串,您可以像这样注释您的函数:
如果您的文件名为
test.py
,您可以然后在安装 mypy 后通过从命令行运行mypy test.py
进行类型检查。如果您使用的是不支持函数注释的旧版 Python,则可以使用类型注释来实现相同的效果:
您对 Python 3 文件使用相同的命令
mypy test.py
,并且 < code>mypy --py2 test.py 用于 Python 2 文件。Python 解释器在运行时完全忽略类型注释,因此它们会产生最小甚至没有开销——通常的工作流程是处理代码并定期运行 mypy 以捕获错误和错误。 某些 IDE(例如 PyCharm)可以理解类型提示,并可以在您直接编辑时提醒您代码中的问题和类型不匹配。
如果出于某种原因,您需要在运行时检查类型(也许您需要验证大量输入?),您应该遵循其他答案中列出的建议 - 例如使用
isinstance
、issubclass
等。 还有一些库,例如 enforce 尝试在运行时执行类型检查(尊重您的类型注释),尽管我不确定截至撰写本文时它们的生产准备情况如何。有关更多信息和详细信息,请参阅 mypy 网站、mypy 常见问题解答,以及PEP 484。
Python now supports gradual typing via the typing module and mypy. The
typing
module is a part of the stdlib as of Python 3.5 and can be downloaded from PyPi if you need backports for Python 2 or previous version of Python 3. You can installmypy
by runningpip install mypy
from the command line.In short, if you want to verify that some function takes in an int, a float, and returns a string, you would annotate your function like so:
If your file was named
test.py
, you could then typecheck once you've installed mypy by runningmypy test.py
from the command line.If you're using an older version of Python without support for function annotations, you can use type comments to accomplish the same effect:
You use the same command
mypy test.py
for Python 3 files, andmypy --py2 test.py
for Python 2 files.The type annotations are ignored entirely by the Python interpreter at runtime, so they impose minimal to no overhead -- the usual workflow is to work on your code and run mypy periodically to catch mistakes and errors. Some IDEs, such as PyCharm, will understand type hints and can alert you to problems and type mismatches in your code while you're directly editing.
If, for some reason, you need the types to be checked at runtime (perhaps you need to validate a lot of input?), you should follow the advice listed in the other answers -- e.g. use
isinstance
,issubclass
, and the like. There are also some libraries such as enforce that attempt to perform typechecking (respecting your type annotations) at runtime, though I'm uncertain how production-ready they are as of time of writing.For more information and details, see the mypy website, the mypy FAQ, and PEP 484.
这会检查
n
是否为 Python int,并且仅为 int。 它不接受int
的子类。然而,类型检查并不适合“Python 方式”。 您最好将
n
用作 int,如果它抛出异常,则捕获它并对其采取行动。This checks if
n
is a Python int, and only an int. It won't accept subclasses ofint
.Type-checking, however, does not fit the "Python way". You better use
n
as an int, and if it throws an exception, catch it and act upon it.不要输入检查。 鸭子打字的重点是你不应该这样做。 例如,如果有人做了这样的事情怎么办:
Don't type check. The whole point of duck typing is that you shouldn't have to. For instance, what if someone did something like this:
使用 Python 编程并像使用其他语言一样执行类型检查确实看起来像是选择一把螺丝刀来敲钉子。 使用Python的异常处理功能更加优雅。
从交互式命令行,您可以运行如下语句:
这将生成错误 - ipython 告诉我:
现在您可以编写一些代码,如:
可以自定义它来执行所需的任何操作并捕获任何预期的错误。 它看起来有点复杂,但符合 Python 的语法和习惯用法,并且会产生非常可读的代码(一旦您习惯使用 Python)。
Programming in Python and performing typechecking as you might in other languages does seem like choosing a screwdriver to bang a nail in with. It is more elegant to use Python's exception handling features.
From an interactive command line, you can run a statement like:
That will generate an error - ipython tells me:
Now you can write some code like:
That can be customised to perform whatever operations are required AND to catch any errors that are expected. It looks a bit convoluted but fits the syntax and idioms of Python and results in very readable code (once you become used to speaking Python).
我很想这样做:
这样,当您使用它时,任何东西都可以传入,但您只存储一个有效的整数。
I would be tempted to to something like:
That way when you are using it anything can be passed in yet you only store a valid integer.
怎么样:
当然有标准的 isinstance(3, int) 函数......
how about:
ofcourse there is the standard isinstance(3, int) function ...
对于那些希望使用assert()函数来做到这一点的人。 以下是如何在代码中有效地放置变量类型检查而无需定义任何其他函数。 如果出现assert() 错误,这将阻止您的代码运行。
如果没有引发错误,代码将继续工作。 除此之外,
unittest
模块对于此类事情来说是一个非常有用的工具。For those who are looking to do this with assert() function. Here is how you can efficiently place the variable type check in your code without defining any additional functions. This will prevent your code from running if the assert() error is raised.
If no error was raised, code continues to work. Other than that,
unittest
module is a very useful tool for this sorts of things.