为什么 mypy `cast` 只在某些时候有效?
why does mypy `cast` only work some of the time?
首先我做了一个傻乎乎的小东西class
# 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]
。奶酪也没有注释,而且效果很好。
我确定要使最后一行工作,我需要 get/make 一些 lxml 注释。但是我的 cast
被完全忽略了,这对我来说似乎很奇怪。我投射到 Cheese class 并且它起作用了。我投射到 HtmlElement class 但它没有。
我的问题是为什么?
您使用的是旧版本的 mypy 吗?当我尝试使用 mypy 0.630(pypi 上的最新版本)和他们的 git master 分支上的最新代码对您的代码进行类型检查时,我在所有三种情况下都得到了 builtins.list[Any]
的显示类型。
这个显示的类型希望更直观一些——问题是不幸的是 typeshed 上的 lxml
库没有可用的存根,这意味着 mypy 没有关于什么的信息html.HtmlElement
确实是。 (据 mypy 所知,这可能是一个 class、一个函数、一个变量、一个类型别名、一个 namedtuple...)
因此,它放弃并假定它具有 Any
的类型。
这也解释了为什么将 get_some_relevant_elements
的输出分配给 List[bool]
可以正常工作。 List[Any]
类型的变量理论上可以包含任何内容,包括布尔值——所以 可能 这是一个安全的赋值。
无论如何,如果您不喜欢这种行为,您的两个选择是:
接受 lxml
库没有类型 hints/is 纯动态类型,并设计您的代码,以便所有动态都包含在一个位置。当您从 XML 文件中提取信息时,(可选)验证它们并 return 您自己的自定义注释 classes。基本上,故意在代码库的动态部分和非动态部分之间设置一个屏障。
为 lxml 创建您自己的存根。这些存根不一定需要很复杂——为您需要的少数 classes 和方法创建初步存根可能就足够了。 (如果它们最终变得相当充实,如果您愿意的话,您也许可以开源它们并回馈社区。)
首先我做了一个傻乎乎的小东西class
# 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]
。奶酪也没有注释,而且效果很好。
我确定要使最后一行工作,我需要 get/make 一些 lxml 注释。但是我的 cast
被完全忽略了,这对我来说似乎很奇怪。我投射到 Cheese class 并且它起作用了。我投射到 HtmlElement class 但它没有。
我的问题是为什么?
您使用的是旧版本的 mypy 吗?当我尝试使用 mypy 0.630(pypi 上的最新版本)和他们的 git master 分支上的最新代码对您的代码进行类型检查时,我在所有三种情况下都得到了 builtins.list[Any]
的显示类型。
这个显示的类型希望更直观一些——问题是不幸的是 typeshed 上的 lxml
库没有可用的存根,这意味着 mypy 没有关于什么的信息html.HtmlElement
确实是。 (据 mypy 所知,这可能是一个 class、一个函数、一个变量、一个类型别名、一个 namedtuple...)
因此,它放弃并假定它具有 Any
的类型。
这也解释了为什么将 get_some_relevant_elements
的输出分配给 List[bool]
可以正常工作。 List[Any]
类型的变量理论上可以包含任何内容,包括布尔值——所以 可能 这是一个安全的赋值。
无论如何,如果您不喜欢这种行为,您的两个选择是:
接受
lxml
库没有类型 hints/is 纯动态类型,并设计您的代码,以便所有动态都包含在一个位置。当您从 XML 文件中提取信息时,(可选)验证它们并 return 您自己的自定义注释 classes。基本上,故意在代码库的动态部分和非动态部分之间设置一个屏障。为 lxml 创建您自己的存根。这些存根不一定需要很复杂——为您需要的少数 classes 和方法创建初步存根可能就足够了。 (如果它们最终变得相当充实,如果您愿意的话,您也许可以开源它们并回馈社区。)