我正在尝试用Python编写一个树节点类。我有一个名为Node
的基类,它定义了树语义和实现包含不同类型内容的节点的子类。我想使用类型提示
这里是一个最小的实现,它创建字符串或整数的树并首先枚举它们
from typing import TypeVar, Generic, List, Iterable
T = TypeVar("T")
class Node(Generic[T]):
def __init__(self, content: T):
self.content = content
self.children: List[Node[T]] = []
def depth_first_search(self) -> Iterable["Node[T]"]:
yield self
for child in self.children:
yield from child.depth_first_search()
class StringNode(Node[str]):
def get_string(self) -> str:
return self.content
class IntegerNode(Node[int]):
def get_integer(self) -> int:
return self.content
if __name__ == "__main__":
a = StringNode("apple")
b = StringNode("banana")
c = StringNode("pear")
a.children = [b, c]
for n in a.depth_first_search():
print(n.get_string())
a = IntegerNode(1)
b = IntegerNode(2)
c = IntegerNode(3)
a.children = [b, c]
for n in a.depth_first_search():
print(n.get_integer())
然而,这段代码在运行时工作,从PyCharm中,我分别得到了n.get_string()
和n.get_integer()
行的警告“未解析属性引用'get_string'用于类'Node'”和“未解析属性引用'get_integer'用于类'Node'”
我尝试过为类型变量T
指定各种covariant
和contravariant
修饰符。在Python3.7中,我还尝试使用PEP 563,添加from __future__ import annotations
并从Node.depth_first_search
的返回值提示中删除引号。所有这些都没有产生效果
我曾尝试在StringNode
中创建如下“类型转换”方法
def depth_first_search(self) -> Iterable[StringNode]:
return super().depth_first_search()
这将处理__main__
块中的警告,但现在我在该方法的返回值上得到了“预期类型'Iterable[StringNode]',而不是'Iterable[Node]'警告
如何重写类型提示以避免收到警告
如果我将
Node
作为基类,那么似乎没有一种方法可以使用Python的类型暗示来获得我想要的结果。但是,我可以通过将Node
更改为mixin使其工作这运行正确,PyCharm没有给我任何警告。此外,如果我错误地尝试调用
upper
或add_five
由NodeMixin.depth_first_search
返回的错误类型的对象,我会收到警告当
a
是StringNode
时,a.depth_first_search()
返回Iterable[Node[str]]
,而不是Iterable[StringNode]
在这种情况下,您可能不应该使用那些
get_string
和get_integer
方法。只要让客户机直接访问content
,或者如果出于某种原因决定使用getter,则将其设置为get_content(self) -> T
基类中的Node
我认为Python的类型注释不支持
depth_first_search
返回所需子类类型的iterable,而不使用显式强制转换或Any
。您需要能够表达这样一个事实,即self
与self.children
的元素具有相同的类型,而我看不到实现这一点的方法相关问题 更多 >
编程相关推荐