流行的 Python 类型检查器对 Any 注释给出漏报

sho*_*qie 1 python types static-analysis

我使用 4 个常见的 Python 类型检查器测试了以下代码片段,令我惊讶的是,它们都没有抱怨:

\n
from typing import Any\n\ndef length(s: str) -> int:\n    return len(s)\n\ndef any_length(o: Any) -> int:\n    return length(o)\n\nif __name__ == "__main__":\n    print(any_length(1234))\n
Run Code Online (Sandbox Code Playgroud)\n

很容易预测运行此代码将导致异常:

\n
TypeError: object of type \'int\' has no len()\n
Run Code Online (Sandbox Code Playgroud)\n

我的

\n
Success: no issues found in 1 source file\n
Run Code Online (Sandbox Code Playgroud)\n

py类型

\n
Success: no errors found\n
Run Code Online (Sandbox Code Playgroud)\n

皮赖特

\n
0 errors, 0 warnings, 0 informations\nCompleted in 0.435sec\n
Run Code Online (Sandbox Code Playgroud)\n

柴堆

\n
\xc6\x9b No type errors found\n
Run Code Online (Sandbox Code Playgroud)\n

我期望至少有一个警告说它Any不是 的子类型str,因此应用于length: str -> int该类型的对象Any是不安全的。这些特定类型是否存在某些问题导致类型检查器难以考虑这种简单的情况?确定一个具体类型是否是另一个具体类型的子类型的问题似乎不是不可确定的,但也许我错了?

\n

che*_*ner 6

Any不仅仅是 的同义词object

Any有点像任何类型的超类型任何类型的子类型,而object是所有类型的超类型但只是其自身的子类型。(这并不是说它Any 任何类型的子类型或超类型,因为Any它不是类型。)

直观地说,

  1. 如果函数需要 type 的值Any,它将接受任何内容,就像通用Any超类型一样。

  2. 但无论函数期望什么,它都会接受 type 的值Any,就好像它Any是通用子类型一样。

更完整的描述可以在 PEP 484 中的渐进类型总结“类型提示理论”Any中找到。但类型基本上允许您对不提供所有内容提示的代码进行类型检查。如果某些东西没有类型提示,则假定它具有 type ,这意味着它的使用方式没有静态限制,就像您对动态类型语言所期望的那样。AnyAny


o具体来说,由于is的静态类型,它是需要 a 的Any函数的有效参数(与一致)。这并不意味着会在运行时工作,因为您基本上对传递给 的值类型撒了谎。lengthstrAnystrany_length(1234)any_lengthlength

  • 更详细地说,如果您想要类型检查并且想要支持 _any_ 类型(实际上是一种类型),请使用“object”,而不是“Any”。理论上,不是“def any_length(o: Any) -> int: ...”,而是“def any_length(o: object) -> int: ...”。(但实际上,“def any_length(o: Sized) -> int:”可能更好。) (3认同)
  • 我应该从我的答案中删除这个措辞,因为“Any”本身不是类型,只是类型类的“扩展”,允许定义“与一致”关系。 (2认同)