如何解决VSCode:使用非本地导致变量类型“从不”
我发现 VSCode/Pylance 有一些 Python 代码的奇怪行为。考虑以下最小示例:
#!/usr/bin/env python3
from typing import Optional
def main():
x: Optional[list] = None
def f():
nonlocal x
x = [10]
f()
assert isinstance(x,list)
y: int = x[0] + 3
assert isinstance(y,int)
print(y)
main()
对 f() 的调用显然将外部 x
设置为 [10]
。将鼠标悬停在第一个 x
语句中的 assert
上(在函数调用之后)显示 (variable) x: None
,这是可以的。但是在 assert
语句之后,将鼠标悬停在 x 上会显示 (variable) x: Never
。这会导致语法高亮和自动完成在所有后续行中都失败 x
,因为 VSCode/Pylance 显然看到了一个“无类型”的变量。键入 x.
甚至不会显示对象的内置成员,如 x.__class__
或 x.__doc__
。将 x
分配给另一个类型变量没有帮助。第一个断言使 mypy 接受代码,而 PyLint 说 Value 'x' is unsubscriptable
,因此其他工具之间似乎也存在一些分歧。这有点烦人,因为代码可以正常工作。
问题:这是 Pylance 中的错误吗?甚至预期的行为?有没有办法强制 Pylance 看到正确的 x
类型?
工具版本:
$ code --version
1.56.2
054a9295330880ed74ceaedda236253b4f39a335
x64
$ pylint --version
pylint 2.8.2
astroid 2.5.6
Python 3.8.5 (default,Jan 27 2021,15:41:15)
[GCC 9.3.0]
$ mypy --version
mypy 0.800
VSCode Python:v2021.5.842923320
VSCode Pylance:v2021.5.3
谢谢和最好的问候,
菲利普
编辑:在 GitHub
上发布了问题解决方法
根据关于GitHub的讨论,我将回答如下问题:
-
这是 Pylance 中的错误吗? 不是错误,但是 Pyright(Pylance 的类型检查器)中实现的类型推断没有考虑由外部执行流(例如作为包含
nonlocal
的回调函数的运行)。 -
或者甚至是预期的行为?是的,至少部分考虑到上述要点。
-
有没有办法强制 Pylance 看到正确的
x
类型?是的,在x = cast(list,x)
之后使用assert isinstance(x,list)
。
使用 cast
,最小示例如下所示:
#!/usr/bin/env python3
from typing import Optional,cast
def main():
x: Optional[list] = None
def f():
nonlocal x
x = [10]
f()
assert isinstance(x,list)
x = cast(list,x)
y: int = x[0] + 3 # Now x is reported as '(variable) x: list'
assert isinstance(y,int)
print(y)
main()
再总结一下 GitHub 问题中的解释:行 x: Optional[list] = None
使 x
的类型为 None
,因为它实际上是这样的,无论类型如何宣布。现在,缺少对函数x
内部f
突变的分析,当到达x
行时None
的类型仍然是assert isinstance(x,list)
。由于类型 None
不是 list
的实例,对于类型检查器,这一行永远不会通过。为了表明这一点,x
的类型因此设置为 Never
。
虽然将鼠标悬停在 x
上会显示 (variable) x: Never
,但是在 Settings.json 中添加 "debug.inlineValues": true
然后 Start Debugging 时,您可以看到x
作为一个特殊的变量,它的属性__class__
确实是list
:
当设置 Jedi 为语言服务器时,将鼠标悬停在 x 上是 NoneType
或 list
:
您可以在 github/pylance-release 中寻求更多帮助。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。