使用TypeVar绑定到协议的Python
我正在尝试将python模块中的类型合并到以下错误中:
类型参数“ nedineins.dict [nelidins.int,edgeight'1]”的“ GraphBase”必须是“ union [typing.mutableset [incelions.int],typing.mutableMapping [hindins.int,so.geweightprotocol]]“
我想支持具有任意边缘权重对象的图形,只要可以订购它们。我的注释尝试是定义edgeweight
typeVar绑定到edge> edgeweightprotocol
协议类。我知道,EdgeWeight实例将不是EdgeWeight Protocol的子类,但它是一个协议,因此根据其定义,它应该具有___ lt ____
方法。
我对仿制药,类型和协议的理解在哪里出错?还是这是一个错误?应该如何支持?
我一直在使用mypy 0.910
import collections.abc
from abc import ABCMeta, abstractmethod
from collections import UserList
from typing import (
Any,
Callable,
Dict,
Iterable,
MutableMapping,
MutableSet,
Protocol,
Set,
Tuple,
TypeVar,
Union,
)
Edge = Tuple[int, int]
EdgeWeight = TypeVar("EdgeWeight", bound="EdgeWeightProtocol")
Graph = TypeVar("Graph", bound="GraphBase[Any]")
class EdgeWeightProtocol(Protocol):
def __lt__(self: EdgeWeight, other: EdgeWeight) -> bool:
...
S = TypeVar("S", bound=Union[MutableSet[int], MutableMapping[int, EdgeWeightProtocol]])
class GraphBase(UserList[S], metaclass=ABCMeta):
_item_type: Callable[..., S]
def __init__(self, n_or_initlist: Union[Iterable[S], int, None] = None,) -> None:
"""
Initializer for GraphBase.
Parameters
----------
n_or_initlist : int or iterable, optional
If `None` (default) initializes a graph of zero order and zero size
(i.e. no vertices and no edges). If int, initializes a graph of
order `n_or_initlist` and zero size. Otherwise initialize the graph
using the iterable `n_or_initlist`.
"""
if n_or_initlist is None:
super().__init__()
elif isinstance(n_or_initlist, int):
super().__init__((self._item_type() for _ in range(n_or_initlist)))
elif isinstance(n_or_initlist, collections.abc.Iterable):
super().__init__(map(self._item_type, n_or_initlist))
else:
raise ValueError(
f"Unsupported type '{type(n_or_initlist).__name__}', "
"expected int or iterable"
)
@abstractmethod
def remove_edge(self, edge: Edge) -> None:
pass
@abstractmethod
def get_edge_weight(self, edge: Edge) -> EdgeWeightProtocol:
pass
class WeightedGraph(GraphBase[Dict[int, EdgeWeight]]):
_item_type = dict
def add_edge(self, edge: Edge, weight: EdgeWeight) -> None:
j, i = edge
self.data[j][i] = weight
def remove_edge(self, edge: Edge) -> None:
j, i = edge
del self.data[j][i]
def get_edge_weight(self, edge: Edge) -> EdgeWeight:
j, i = edge
return self.data[j][i]
class UnweightedGraph(GraphBase[Set[int]]):
_item_type = set
def add_edge(self, edge: Edge) -> None:
j, i = edge
self.data[j].add(i)
def remove_edge(self, edge: Edge) -> None:
j, i = edge
self.data[j].remove(i)
def get_edge_weight(self, _edge: Edge) -> float:
# Always return an edge weight of 1 for an unweighted graph
return 1
I'm trying to incorporate type checking in a Python module and I am stuck at the following error:
Type argument "builtins.dict[builtins.int, EdgeWeight`1]" of "GraphBase" must be a subtype of "Union[typing.MutableSet[builtins.int], typing.MutableMapping[builtins.int, so.EdgeWeightProtocol]]"
I want to support graphs with arbitrary edge weights objects, as long as they can be ordered. My attempt to annotate this was to define an EdgeWeight
TypeVar bound to a EdgeWeightProtocol
Protocol class. I understand that an EdgeWeight instance will not be a subclass of EdgeWeightProtocol, but it's a Protocol so it should have a ___lt___
method according to its definition.
Where is my understanding of Generics, TypeVars, and Protocols going wrong? Or is this a bug? How should this be supported?
I have been using mypy 0.910
import collections.abc
from abc import ABCMeta, abstractmethod
from collections import UserList
from typing import (
Any,
Callable,
Dict,
Iterable,
MutableMapping,
MutableSet,
Protocol,
Set,
Tuple,
TypeVar,
Union,
)
Edge = Tuple[int, int]
EdgeWeight = TypeVar("EdgeWeight", bound="EdgeWeightProtocol")
Graph = TypeVar("Graph", bound="GraphBase[Any]")
class EdgeWeightProtocol(Protocol):
def __lt__(self: EdgeWeight, other: EdgeWeight) -> bool:
...
S = TypeVar("S", bound=Union[MutableSet[int], MutableMapping[int, EdgeWeightProtocol]])
class GraphBase(UserList[S], metaclass=ABCMeta):
_item_type: Callable[..., S]
def __init__(self, n_or_initlist: Union[Iterable[S], int, None] = None,) -> None:
"""
Initializer for GraphBase.
Parameters
----------
n_or_initlist : int or iterable, optional
If `None` (default) initializes a graph of zero order and zero size
(i.e. no vertices and no edges). If int, initializes a graph of
order `n_or_initlist` and zero size. Otherwise initialize the graph
using the iterable `n_or_initlist`.
"""
if n_or_initlist is None:
super().__init__()
elif isinstance(n_or_initlist, int):
super().__init__((self._item_type() for _ in range(n_or_initlist)))
elif isinstance(n_or_initlist, collections.abc.Iterable):
super().__init__(map(self._item_type, n_or_initlist))
else:
raise ValueError(
f"Unsupported type '{type(n_or_initlist).__name__}', "
"expected int or iterable"
)
@abstractmethod
def remove_edge(self, edge: Edge) -> None:
pass
@abstractmethod
def get_edge_weight(self, edge: Edge) -> EdgeWeightProtocol:
pass
class WeightedGraph(GraphBase[Dict[int, EdgeWeight]]):
_item_type = dict
def add_edge(self, edge: Edge, weight: EdgeWeight) -> None:
j, i = edge
self.data[j][i] = weight
def remove_edge(self, edge: Edge) -> None:
j, i = edge
del self.data[j][i]
def get_edge_weight(self, edge: Edge) -> EdgeWeight:
j, i = edge
return self.data[j][i]
class UnweightedGraph(GraphBase[Set[int]]):
_item_type = set
def add_edge(self, edge: Edge) -> None:
j, i = edge
self.data[j].add(i)
def remove_edge(self, edge: Edge) -> None:
j, i = edge
self.data[j].remove(i)
def get_edge_weight(self, _edge: Edge) -> float:
# Always return an edge weight of 1 for an unweighted graph
return 1
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论