我正在尝试注释一个只返回两个值的迭代器,T
和 cls[T]
。
目前我有这样的注释:
from __future__ import annotations
import typing
class Node(typing.Generic[T]):
def __init__(self, value: T, next: typing.Optional[Node[T]] = None) -> None:
self.value = value
self.next = next
def __iter__(self) -> typing.Iterator[typing.Union[T, Node[T]]]:
yield from (self.value, self.next)
这段代码没有任何错误。但是,我希望利用这个 dunder 方法总是产生两个值这一事实来简化用户的过程。
实际上,用户必须处理以下内容:
one = Node[int](1, Node[int](2))
value, next = one # value = 1, next = Node(2) (i.e one.next)
# This is a typing error because next can be either int or Node[int]
# and 'two' is expected to be Node[int]:
two: Node[int] = next
# we can fix this by doing type narrowing
assert isinstance(next, Node)
two = next # now the error should be gone
所以基本上我想利用这样一个事实,即 __iter__
返回的第二个东西总是类型 Node[T]
以避免必须进行类型缩小.
我知道我必须在方法的返回注释中更改 typing.Union[T, Node[T]]
,但我不知道将其更改为什么。
最佳答案
这不可能使用通用的 Iterator
进行注释。它是一个需要 one 类型参数的类。 (当前 typeshed source )这意味着其 __next__
方法返回的每个 值必须具有相同的类型。
您正在 self.value, self.next
元组上调用迭代器协议(protocol)。一个元组有任意 数量的类型参数(参见 here ),但它上面的迭代器必须只有一个。这实际上经常导致打字问题。
由于您似乎打算让您的 Node
类从本质上模拟 tuple
接口(interface),这可能是极少数情况之一,最好直接从它继承. tuple
显然也会为您提供可迭代协议(protocol),因此您仍然可以像以前一样解压它,但是如果您做的一切都正确,则应该正确推断类型。
这是一个完整的工作示例:
from __future__ import annotations
from typing import TypeVar, Optional
T = TypeVar("T")
class Node(tuple[T, "Node[T]"]):
def __new__(cls, value: T, next_: Optional[Node[T]] = None) -> Node[T]:
return tuple.__new__(cls, (value, next_))
def __init__(self, value: T, next_: Optional[Node[T]] = None) -> None:
self.value = value
self.next = next_
if __name__ == "__main__":
node_1 = Node(1, Node(2))
val: int
node_2: Node[int]
val, node_2 = node_1
这通过了 mypy --strict
没有问题。
作为不相关的旁注,我建议不要使用内置名称,如 next
.
另外,请注意,当您初始化一个节点时,您不需要为 Node
指定类型参数,因为它会自动绑定(bind)到传递给 的类型>值
参数。
https://stackoverflow.com/questions/74696410/
相关文章:
haskell - 如何测试自定义 StateT 的 Monad 实例?
typescript - 如何在保持默认行为的同时扩展 tsconfig 中的类型
windows-installer - 在 Windows 的添加/删除程序中显示正确的大小
javascript - 是的,当 .required() 为 false 时,会继续在同一个属性上
laravel - 生产模式编译报错 "is not a function"Vue Laravel
node.js - 为什么当我使用 "waitForSelector"时 Puppeeteer 导致