为什么mypy`cast`只能在某些时间工作?

时间:2018-09-25 13:20:34

标签: python mypy

首先我上了一个愚蠢的小课

# cheese_helpers.py
class Cheese:
    pass

然后发生了

# weird.py

import lxml
from typing import cast, List
import cheese_helpers

o: List[Any] = []
reveal_type(o) # builtins.List[Any] as expected

y = cast(List[cheese_helpers.Cheese], o)  
reveal_type(y)  # builtins.List[cheese_helpers.Cheese], as expected

# so far so good. And then:

z = cast(List[lxml.html.HtmlElement], o)  
reveal_type(z) # builtins.List[Any] ???????????????

如果您问我,最后一行应该是List[lxml.html.HtmlElement]。奶酪也没有注释,也很好用。

我确定要使最后一行有效,我需要获取/制作一些lxml注释。但是,我的cast被完全忽略了对我来说似乎很奇怪。我选了芝士课,它起作用了。我强制转换为HtmlElement类,但事实并非如此。

我的问题是为什么?

1 个答案:

答案 0 :(得分:0)

您是否正在使用旧版本的mypy?当我尝试同时使用mypy 0.630(pypi的最新版本)和其git master分支上的最新代码对您的代码进行类型检查时,在这三种情况下,我都得到了显露的builtins.list[Any]类型。

希望这种显示的类型更加直观-问题是,不幸的是,typeshed上的lxml库没有可用的存根,这意味着mypy没有关于{{ 1}}确实是。 (据mypy所知,它可能是一个类,一个函数,一个变量,一个类型别名,一个namedtuple ...)

因此,它放弃了,只是假设它的类型为html.HtmlElement

这也解释了为什么将Any的输出分配给get_some_relevant_elements不会出错。类型为List[bool]的变量理论上可以包含任何内容,包括bool,因此也许这是一个安全的赋值。


无论如何,如果您不喜欢此行为,则有两个选择:

  1. 接受List[Any]库没有类型提示/纯动态输入的信息,并设计代码,以便将所有动态性包含在一个位置。从XML文件提取信息时,(可选)验证它们并返回自己的自定义带注释的类。基本上,故意在代码库的动态和非动态部分之间包含一个障碍。

  2. 为lxml创建您自己的存根。这些存根不必一定很复杂-仅为所需的一些类和方法创建初步存根就足够了。 (如果他们最终变得充实了,如果您愿意的话,您可以开源它们并回馈社区。)