如何在具有通用子类化/继承的 for 循环中使用 mypy 注释?

How to use mypy annotation in a for loop with generic subclassing / inheritance?

我受困于 python mypy 继承和 for 循环。

为了简化这里是 stubs/xml/__init__.pyi 的有效存根:

from typing import Dict,Iterable,Sized,Iterator,List,Optional, TypeVar

T = TypeVar('T', bound='Element')


class Element():
    attrib: Dict[str,str]

    def getchildren(self)->List[T]:...
    def getparent(self)->List[Element]:...
    def drop(self)->None:...

这是 stubs/xml/html/__init__.pyi

中子元素的有效存根
from typing import Sized,Dict,Type,Generic
from xml import Element
import xml

class HtmlElement(xml.Element):...

这是我无法更正的代码:最后一个例子让 mypy 抱怨,这是一个小问题

from typing import List, Dict, Set, Optional, Tuple

from xml.html import HtmlElement
from xml import Element
import xml
import xml.html

a: HtmlElement = HtmlElement()
b: HtmlElement = HtmlElement()

# getparent return ->List[Element]
d: List[Element] = a.getparent()
for d_element in d:
    d_element.drop() # Mypy is ok

for f_element in b.getparent():
    f_element.drop() # Mypy is ok

# getchildren return ->List[T] 
c: List[HtmlElement] = a.getchildren()
for a_element in c:
    a_element.drop()  #Mypy is ok

b_element: HtmlElement # requested by mypy 'Need type annotation for 'b_element'
for b_element in b.getchildren():
    b_element.drop() # Mypy is complaining with : <nothing> has no attribute "drop"

当类型是泛型时,Mypy 似乎不理解预打字,当它在所有其他情况下工作时。

如何在带有泛型子类化/继承的 for 循环中使用 mypy 注释?这是一个 mypy 错误,还是我遗漏了什么?

请注意,这是一个 Mypy(即 Python 注释检查)问题。该方法的真正实现不是本题的主题。

问题与您在 Element 中对 getchildren 的定义有关。

该函数被注释为 return 一些通用的 TypeVar——但是 TypeVar 到底是什么? mypy 不可能推断出 T 应该在那里。元素? Element?

的某个子class

您应该完全停止使用 TypeVars 并将 return 设为 List[Element] 或使 Element class 通用。

from typing import Generic, TypeVar, Dict, List

T = TypeVar('T', bound='Element')

class Element(Generic[T]):
    attrib: Dict[str,str]

    def getchildren(self) -> List[T]: ...
    def getparent(self) -> List[Element]: ...
    def drop(self) -> None: ...

如果我们将类型提示添加回我们通常忽略的 self 参数,这意味着我们已经将 getchildren 的签名从 def getchildren(self: Element) -> List[T] 变成了 def getchildren(self: Element[T]) -> List[T].后一个签名满足在您编写的所有函数和方法签名中必须始终至少使用 TypeVar 两次的规则。

当然,当您子class HTMLElement 并在您的代码中使用任一类型时传播泛型。