首先我上了一个愚蠢的小课
# 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类,但事实并非如此。
我的问题是为什么?
答案 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,因此也许这是一个安全的赋值。
无论如何,如果您不喜欢此行为,则有两个选择:
接受List[Any]
库没有类型提示/纯动态输入的信息,并设计代码,以便将所有动态性包含在一个位置。从XML文件提取信息时,(可选)验证它们并返回自己的自定义带注释的类。基本上,故意在代码库的动态和非动态部分之间包含一个障碍。
为lxml创建您自己的存根。这些存根不必一定很复杂-仅为所需的一些类和方法创建初步存根就足够了。 (如果他们最终变得充实了,如果您愿意的话,您可以开源它们并回馈社区。)