Python 类型提示语法如何/为何起作用?

How / why does Python type hinting syntax work?

我刚在PEP 484看到下面的例子:

def greeting(name: str) -> str:
    return 'Hello ' + name

print(greeting('Martin'))
print(greeting(1))

不出所料,这在 Python 2:

中不起作用
  File "test.py", line 1
    def greeting(name: str) -> str:
                     ^
SyntaxError: invalid syntax

但是,它适用于 Python 3:

Hello Martin
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    print(greeting(1))
  File "test.py", line 2, in greeting
    return 'Hello ' + name
TypeError: Can't convert 'int' object to str implicitly

这出乎意料。它并没有真正检查类型,正如您在下面的示例中看到的那样(它运行,但不抛出异常):

def greeting(name: str) -> int:
    return 'Hello ' + name

print(greeting('Martin'))

好像:后面必须是函数名,但是函数好像被忽略了:

def aha(something):
    print("aha")
    return something+"!"

def greeting(name: aha, foo) -> int:
    return 'Hello ' + name + foo

print(greeting('Martin', 'ad'))

->之后的名字似乎也是如此。

这种类型提示语法是否使用了其他东西(例如 Java 建模语言使用注释)? Python 是什么时候引入这种语法的?有没有办法使用此语法进行静态类型检查?它总是破坏 Python 2 兼容性吗?

这里没有类型提示。您所做的只是提供 annotations;这些是用 PEP 3107 引入的(仅在 Python 3 中,在 Python 2 中不支持);它们允许您使用任意信息注释参数和 return 值以供以后检查:

>>> greeting.__annotations__
{'name': <class 'str'>, 'return': <class 'str'>}

这里根本不咨询他们。相反,您收到的错误消息是尝试在函数体:

中连接字符串和整数值
>>> 'Hello ' + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly

这是一个自定义类型错误,旨在提供有关 str + int 串联失败原因的附加信息;对于任何不是 str:

的类型,它由 str.__add__ 方法抛出
>>> ''.__add__(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly
>>> ''.__add__(True)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'bool' object to str implicitly

PEP 484 然后建议利用这些注释通过 其他工具 进行实际的静态类型检查,但正如 PEP 的介绍所述:

While these annotations are available at runtime through the usual __annotations__ attribute, no type checking happens at runtime. Instead, the proposal assumes the existence of a separate off-line type checker which users can run over their source code voluntarily. Essentially, such a type checker acts as a very powerful linter.

强调原文。

PEP 的灵感来自于使用 PEP 3107 注释的现有工具;特别是 mypy project (which is looping right back by adopting PEP 484), but also the type hinting support in the PyCharm IDE and the pytypedecl project. See Guido van Rossum's original email kickstarting this effort as well as a follow-up email.

mypy 显然支持 Python 2 通过预处理注释,在为你字节编译源代码之前删除它们,但是你通常不能使用语法 Python 代码来工作 Python 2.

PEP 484 还描述了 stub files 的使用,它位于常规 Python 文件旁边;这些使用 .pyi 扩展名并且只包含签名(带有类型提示),留下主要的 .py 文件注释,因此可以在 Python 2 上使用(前提是你写了 Polyglot Python 代码)。