Mypy 函数“lxml.etree.ElementTree”作为类型无效,但为什么呢?

问题描述 投票:0回答:2

我正在使用 Mypy 来实现这个功能

import funcy as fu
from lxml import etree
from lxml.etree import Element, ElementTree

def find_nodes(tree: ElementTree, paths: Iterable[str]) -> Iterable[Element]:
    """Yield all non-zero nodes for the given paths in the tree."""
    return fu.remove(fu.isnone, map(tree.find, paths))

用 mypy (0.942) 和 lxml-stubs 检查这个文件给我这个奇怪的错误:

xxx\layout\treeutils.py:9: error: Function "lxml.etree.ElementTree" is not valid as a type
xxx\layout\treeutils.py:9: note: Perhaps you need "Callable[...]" or a callback protocol?

我该如何解决?

python lxml mypy typing
2个回答
1
投票

lxml-stubs
中,
ElementTree
确实被声明为一个函数。它返回一个
_ElementTree
类型的对象,它 被声明为一个类。
Element
_Element
也发生了类似的事情。

查看

lxml
本身,事实证明这是正确的:
_ElementTree
defined 作为 Cython 类,
ElementTree
defined 作为函数。我对 Cython 的了解还不够多,无法说明为什么要这样实现。

所以这有效:

from lxml.etree import Element, ElementTree, _Element, _ElementTree

def find_nodes(tree: _ElementTree, paths: Iterable[str]) -> Iterable[_Element]:

我不会太担心这里的下划线。单个下划线只是指示受保护类型的约定,对 Python 解释器没有特殊含义。如果 lxml 选择在其公共 API 中公开此类类型作为返回值,那么它们很可能在 lxml 的未来版本中不会出现。您的选择是使用这些类型并享受某种类型安全,或者求助于

Any
并且根本没有类型安全。


0
投票

为了补充 Thomas 的回答,

etree.ElementTree()
是一个创建
etree._ElementTree
对象的工厂函数。
etree.Element()
etree._Element
相同。因此,函数签名应该是:

def find_nodes(tree: _ElementTree, paths: Iterable[str]) -> Iterable[_Element]:
    ...

顺便说一句,欢迎您查看我的版本

types-lxml
,它完全取代了
lxml-stubs
,因为最新版本功能完整。当使用
types-lxml
进行类型检查时,您需要在
_ElementTree
上添加下标,表示树包含的元素类型:

def find_nodes(tree: _ElementTree[_Element], paths: Iterable[str]) -> Iterable[_Element]:
    ...
© www.soinside.com 2019 - 2024. All rights reserved.