如何在Python中键入检查变量?

时间:2009-01-20 23:58:45

标签: python typing dynamic-typing

我有一个Python函数,它接受一个必须为整数的数字参数,以使其行为正确。在Python中验证这个的首选方法是什么?

我的第一反应是做这样的事情:

def isInteger(n):
    return int(n) == n

但我不禁想到这是1)昂贵的2)丑陋和3)受到机器epsilon的温柔怜悯。

Python是否提供任何本地的类型检查变量方法?或者这被认为违反了语言的动态类型设计?

编辑:由于许多人问过 - 有问题的应用程序使用IPv4前缀,从平面文本文件中获取数据。如果任何输入被解析为浮点数,那么该记录应被视为格式错误并被忽略。

9 个答案:

答案 0 :(得分:32)

isinstance(n, int)

如果你需要知道它是否是一个真正的int而不是int的子类(通常你不需要这样做):

type(n) is int

这样:

return int(n) == n

不是一个好主意,因为跨类型比较可能是真的 - 尤其是int(3.0)==3.0

答案 1 :(得分:16)

是的,正如埃文所说,不要打字检查。只是尝试使用值:

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'

它显示了一个错误,TypeError,无论如何都应该这样做。如果来电者想要抓住这个,那就有可能。

如果做了类型检查,你会怎么做?显示错误对吗?因此,您不必进行类型检查,因为错误已经自动显示。

此外,由于您没有进行类型检查,因此您可以使用其他类型的功能:

浮标:

>>> 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

所以你很明显没有得到什么。并且失去了很多。


更新:

由于您已经编辑了问题,现在很清楚您的应用程序调用了一些仅对int有意义的上游例程。

在这种情况下,我仍然认为你应该将参数作为接收传递给上游功能。上游功能将正确处理它,例如如果需要,会引发错误。我高度怀疑如果你传递一个浮点数,你处理IP的函数会表现得很奇怪。如果您能给我们提供图书馆的名称,我们可以为您检查。

但是......如果上游函数的行为不正确并且杀了一些孩子,如果你把它传给了一个浮点数(我仍然高度怀疑它),那么只需在它上面调用int()

def myintfunction(value):
   """ Please pass an integer """
   return upstreamfunction(int(value))

你仍然没有进行类型检查,所以你得到的不是类型检查的好处。


即使在所有这些之后,你真的想要键入check,尽管它会降低你的应用程序的可读性和性能而绝对没有任何好处,但使用assert来执行此操作。

assert isinstance(...)
assert type() is xxxx

这样我们可以关闭assert并从程序中删除此<sarcasm> 功能 </sarcasm>,将其称为

python -OO program.py

答案 2 :(得分:4)

if type(n) is int

检查n是否为Python int,是否为int。它不接受int的子类。

然而,类型检查不适合“Python方式”。最好使用n作为int,如果它抛出异常,请抓住它并对其进行操作。

答案 3 :(得分:4)

Python现在通过gradual typingtyping module支持mypy。 {* 1}}模块是从Python 3.5开始的stdlib的一部分,如果需要Python 2的后端口或Python 3的早期版本,可以下载from PyPi。您可以通过运行安装typing来自命令行的mypy

简而言之,如果你想验证某个函数是否包含int,float,并返回一个字符串,你可以像这样注释你的函数:

pip install mypy

如果您的文件名为def foo(param1: int, param2: float) -> str: return "testing {0} {1}".format(param1, param2) ,则可以通过从命令行运行test.py来安装mypy后进行类型检查。

如果您使用旧版本的Python而不支持功能注释,则可以使用类型注释来实现相同的效果:

mypy test.py

对Python 3文件使用相同的命令def foo(param1, param2): # type: (int, float) -> str return "testing {0} {1}".format(param1, param2) ,对Python 2文件使用mypy test.py

Python解释器在运行时完全忽略了类型注释,因此它们只需要很少的开销 - 通常的工作流程是处理代码并定期运行mypy来捕获错误和错误。某些IDE(例如PyCharm)会理解类型提示,并且可以在您直接编辑时提醒您注意问题并输入代码中的不匹配。

如果由于某种原因,您需要在运行时检查类型(可能需要验证大量输入?),您应该遵循其他答案中列出的建议 - 例如使用mypy --py2 test.pyisinstance等。还有一些库,例如enforce,它们试图在运行时执行类型检查(尊重你的类型注释),尽管我不确定它们在编写时的生产准备情况。

有关详情和详情,请参阅mypy websitemypy FAQPEP 484

答案 4 :(得分:1)

请勿键入支票。鸭子打字的重点是你不应该这样做。例如,如果某人做了类似这样的事情,那该怎么办:

class MyInt(int):
    # ... extra stuff ...

答案 5 :(得分:1)

使用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)。

答案 6 :(得分:0)

我会想要这样的事情:

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)

当你使用它时,任何东西都可以传入但你只存储一个有效的整数。

答案 7 :(得分:0)

怎么样:

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

当然有标准的isinstance(3,int)函数......

答案 8 :(得分:0)

对于那些希望使用assert()函数实现此目的的人。这是您可以在不定义任何其他功能的情况下将变量类型检查有效地放入代码中的方法。如果出现assert()错误,这将阻止您的代码运行。

assert(type(X) == int(0))

如果未引发任何错误,则代码将继续工作。除此之外,unittest模块是用于此类事情的非常有用的工具。