如果有多个可能的 return 值,pyright 是否应该根据传递的参数自动推断出正确的值?
If there are multiple possible return values, should pyright automatically infer the right one, based on the passed arguments?
我有以下功能:
from lxml import etree
from typing import Union
def _get_inner_xml(element: Union[etree._Element, None]) -> Union[str, None]:
if element is None:
return None
# See
return (str(element.text or "") + "".join(etree.tostring(child, encoding="unicode") for child in element)).strip()
root = etree.fromstring('<html><body>TEXT<br/>TAIL</body></html>')
innerXML = _get_inner_xml(root)
print(innerXML)
我的理解是,如果我将 None
作为参数传递,我总是会得到 None
作为 return 值。另一方面,etree._Element
作为参数将始终导致 str
return.
如果我在 vscode 中使用 pylance 编写以下内容(它在后台使用 pyright):
def test(element: etree._Element):
variable = _get_inner_xml(element)
在这种情况下,我得到类型提示 (variable) variable: str | None
。我希望 pylance 知道变量应该是 str
类型。我在监督什么吗?这可能是一个错误吗?
如果这按预期工作:是否有可能手动告诉 pylance“每当此函数获得 etree._Element
时,它将 return 一个 str
并且每当我通过 None
它 returns None
"?
这不是类型提示的工作方式。要知道 etree._Element
的输入总是导致 etree._Element
的 return 并且 None
的输入总是导致 None
IDE 会需要解析函数,分析所有路径并得到结果。
我非常怀疑它是否适合这样做。相反,IDE 只是解析签名中的注释并将它们 return 作为提示 - 类型提示只是 - 它们不会在代码执行时强制执行。
你可能想用一个更简单的函数来检查:
# this will either return a None or a str - it simply returns what is inputted
def test(element: Union[str, None]) -> Union[str, None]:
return element
should_be_str = test("should be a str as type hint return")
should_be_none = test(None)
should_be_marked_as_type_mismatch = test(42) # works from the signature information
看看你的 IDE 是否捡到那个 - 我很怀疑。
这里的答案是使用typing.overload
(文档here),它允许您为一个函数注册多个不同的签名。用 @overload
装饰的函数定义在运行时会被忽略——它们只是用于类型检查器——所以函数体可以用文字省略号 ...
、pass
填充,或者只是文档字符串。您还需要确保提供不使用 @overload
.
的函数的“具体”实现
from lxml import etree
from typing import Union, overload
@overload
def _get_inner_xml(element: etree._Element) -> str:
"""Signature when `element` is of type `etree._Element`"""
@overload
def _get_inner_xml(element: None) -> None: ...
"""Signature when `element` is of type `None`"""
def _get_inner_xml(element: Union[etree._Element, None]) -> Union[str, None]:
if element is None:
return None
# See
return (str(element.text or "") + "".join(etree.tostring(child, encoding="unicode") for child in element)).strip()
root = etree.fromstring('<html><body>TEXT<br/>TAIL</body></html>')
innerXML = _get_inner_xml(root)
print(innerXML)
我有以下功能:
from lxml import etree
from typing import Union
def _get_inner_xml(element: Union[etree._Element, None]) -> Union[str, None]:
if element is None:
return None
# See
return (str(element.text or "") + "".join(etree.tostring(child, encoding="unicode") for child in element)).strip()
root = etree.fromstring('<html><body>TEXT<br/>TAIL</body></html>')
innerXML = _get_inner_xml(root)
print(innerXML)
我的理解是,如果我将 None
作为参数传递,我总是会得到 None
作为 return 值。另一方面,etree._Element
作为参数将始终导致 str
return.
如果我在 vscode 中使用 pylance 编写以下内容(它在后台使用 pyright):
def test(element: etree._Element):
variable = _get_inner_xml(element)
在这种情况下,我得到类型提示 (variable) variable: str | None
。我希望 pylance 知道变量应该是 str
类型。我在监督什么吗?这可能是一个错误吗?
如果这按预期工作:是否有可能手动告诉 pylance“每当此函数获得 etree._Element
时,它将 return 一个 str
并且每当我通过 None
它 returns None
"?
这不是类型提示的工作方式。要知道 etree._Element
的输入总是导致 etree._Element
的 return 并且 None
的输入总是导致 None
IDE 会需要解析函数,分析所有路径并得到结果。
我非常怀疑它是否适合这样做。相反,IDE 只是解析签名中的注释并将它们 return 作为提示 - 类型提示只是 - 它们不会在代码执行时强制执行。
你可能想用一个更简单的函数来检查:
# this will either return a None or a str - it simply returns what is inputted
def test(element: Union[str, None]) -> Union[str, None]:
return element
should_be_str = test("should be a str as type hint return")
should_be_none = test(None)
should_be_marked_as_type_mismatch = test(42) # works from the signature information
看看你的 IDE 是否捡到那个 - 我很怀疑。
这里的答案是使用typing.overload
(文档here),它允许您为一个函数注册多个不同的签名。用 @overload
装饰的函数定义在运行时会被忽略——它们只是用于类型检查器——所以函数体可以用文字省略号 ...
、pass
填充,或者只是文档字符串。您还需要确保提供不使用 @overload
.
from lxml import etree
from typing import Union, overload
@overload
def _get_inner_xml(element: etree._Element) -> str:
"""Signature when `element` is of type `etree._Element`"""
@overload
def _get_inner_xml(element: None) -> None: ...
"""Signature when `element` is of type `None`"""
def _get_inner_xml(element: Union[etree._Element, None]) -> Union[str, None]:
if element is None:
return None
# See
return (str(element.text or "") + "".join(etree.tostring(child, encoding="unicode") for child in element)).strip()
root = etree.fromstring('<html><body>TEXT<br/>TAIL</body></html>')
innerXML = _get_inner_xml(root)
print(innerXML)