Python类型检查

Python类型检查,python,types,static-analysis,static-typing,Python,Types,Static Analysis,Static Typing,可能重复: 在很大程度上,我喜欢这样一个事实:在Python中,您可以选择任何类型并将其放到您喜欢的地方,然后让Duck类型接管。但是怎样才能阻止这该死的东西通过编译时间呢。有没有一种方法可以在编译时强制执行某种类型的健全性检查,而无需进行单元测试。没有。Python编译器甚至不知道(通常也不知道)变量名拼写是否正确,更不用说每个变量、对象属性、集合槽中的pup类型了,这不仅仅是因为编写它的人有其他的优先权,对于大多数代码来说,这是很难做到的。对于一些非常简单的情况,静态分析器可能会尝试类似的

可能重复:


在很大程度上,我喜欢这样一个事实:在Python中,您可以选择任何类型并将其放到您喜欢的地方,然后让Duck类型接管。但是怎样才能阻止这该死的东西通过编译时间呢。有没有一种方法可以在编译时强制执行某种类型的健全性检查,而无需进行单元测试。

没有。Python编译器甚至不知道(通常也不知道)变量名拼写是否正确,更不用说每个变量、对象属性、集合槽中的pup类型了,这不仅仅是因为编写它的人有其他的优先权,对于大多数代码来说,这是很难做到的。对于一些非常简单的情况,静态分析器可能会尝试类似的方法。但实际上,这是不可能的。

Python并没有像其他静态语言那样定义良好的“编译时”


您可以使用
isinstance()
type()
来验证您的对象是否是您所期望的类的实例。

使用类似的单独工具来警告您不存在的方法或属性的用法。这不是编译的一部分,但您可以将其作为自己过程的一部分来实施,例如VCS中的预提交挂钩。

您可以将所有内容的第一行设置为:

if not all(isinstance(a, b) for a, b in zip(((x, int), (y, str), (z, float))))
您可以使用这样的包,它允许您显式声明类型


你可以把代码写进去。

我想你只是想快速检查一下,对吗

我将用一个快速演示来回答:

>>> m = 7
>>> m.__class__
<type 'int'>
>>> n = 6
>>> o = 6.6
>>> m.__class__ == n.__class__
True
>>> m.__class__ == o.__class__
False
>>> isinstance(o, int)
False
>>> isinstance(m, int)
True
>>> 
>m=7
>>>硕士班__
>>>n=6
>>>o=6.6
>>>m.uuu类uu==n.uu类__
真的
>>>m.uuu类uuu==o.uu类__
假的
>>>isinstance(o,int)
假的
>>>isinstance(m,int)
真的
>>> 

希望这是有意义的。

Python没有类似的东西,因为编译是初始化时间。您可以使用
assert
语句强制将特定类型传递给您的函数,即
assert type(foo)=list
,但这有点不和谐,因为它首先会破坏duck类型。pythonic就是检查你得到的对象是否有你需要的方法。例如,如果需要迭代对象,请尝试以下操作:

assert '__iter__' in dir(obj)

编译器没有Python中的类型信息;然而,例如,我们已经讨论了向语言添加可选注释以向编译器提供这些信息的可能性


同时,我建议查看,这可能会实现一些您想要的功能。

您可以滥用装饰程序,在调试模式下为异常类型添加警告:

import warnings
import functools
import numbers

debug = True

class TypeWarning(Warning):
    pass

def warn_types(*pos_types):
    def decorator(func):
        if not debug:
            return func
        @functools.wraps(func)
        def wrapper(*args):
            for i, (x, t) in enumerate(zip(args, pos_types)):
                if not isinstance(x, t):
                    warnings.warn("Expected %s got %s for argument %d of %s"
                                        % (t.__name__, x.__class__.__name__,
                                           i, func.__name__),
                                  category=TypeWarning, stacklevel=2)
            return func(*args)
        return wrapper
    return decorator


@warn_types(numbers.Number, numbers.Number)
def add(x, y):
    return x + y
这会在不破坏功能的情况下为程序员生成警告,并且可以通过关闭调试模式来关闭这些警告。在完成项目编码后,也可以通过简单的搜索替换来删除它们

>>> print add(3, 4)
7
>>> print add("a", "b")
__main__:1: TypeWarning: Expected Number got str for argument 0 of add
__main__:1: TypeWarning: Expected Number got str for argument 1 of add
ab

在一般情况下,为关键字参数扩展它是非常重要的,除非您使用的是Python 3,并且可以利用注释,以防变得非常简单。

+1。重要的是要理解,在Python中,类或函数定义是执行的代码。这些知识会让很多看似疯狂的事情变得非常有意义。是的,我知道这些,只是想也许有一个卑鄙的小选择,可以强制“愚蠢愚蠢的我”不要做愚蠢的事情,并在我真正做之前被警告。嘿,也许我需要的是一台时间机器。Cython不是用来获取静态类型,而是用来编写在C和Python之间运行的代码。事实上,Cython编译器将所有Python对象视为单一类型(
object
)。我知道,但它类似于Python,您可以声明类型。如果他只想对某些特定代码执行此操作,那么这是一个可能的解决方案。不,所有Python对象(与Python本身非常类似)都是“类型化”的,因为只有一个Opaque类型声称在编译时支持所有操作,而在运行时大多数操作都失败。
int
float
等部分只是从一些Python对象隐式转换成的C值,非常有限。您必须编写自己的扩展类型,这简直是过火了,而且不必要的困难。您是说如果在Cython中我使用二进制数据(bytes binary\u data)进行了
def工作
,然后从其他Cython代码中使用字节以外的其他类型(在Cython中声明为bytes),它只会在运行时失败,而不会在编译时失败?哦。我必须承认,我以前的陈述是错误的。我为传播FUD而道歉,尽管我仍然认为使用Cython进行一些静态键入是不切实际的,而且表面上是错误的。不,我知道这类东西。我认为可能有一个很好的编译时选项,来阻止我做一些愚蠢的事情。这种方法的问题是我认为检查会影响运行时性能。编译时检查的美妙之处在于它在运行时不会产生任何性能。但在python中,不可能进行编译时检查,如果调用
python-O
I只能带着悲伤的表情回答这一问题,断言会自动禁用(