转换为自定义集合类的集合在Python中返回空集合



我最近编写了自己的OrderedSet实现,因为我在公开的有序/排序集实现中遇到了问题。该类在后台使用dict代理对象,并且主要转发操作。我实现了所有(在我看来(相关的方法,包括__iter__,并且像list(myset)这样的调用按预期工作。

但是,调用set(myset)总是返回空集。

以下是OrderedSet的完整代码:

from typing import TypeVar, Generic, Optional, Iterable, Set, AbstractSet, Union, Iterator, Any, Dict
T = TypeVar("T")
S = TypeVar("S")

class OrderedSet(Generic[T], Set[T]):
def __init__(self, base: Optional[Union[Dict[T, None], Iterable[T]]] = None):
super().__init__()
self.the_dict: Dict[T, None]
if not base:
self.the_dict = {}
elif isinstance(base, dict):
self.the_dict = base
else:
self.the_dict = dict.fromkeys(base)
def __eq__(self, o: object) -> bool:
return isinstance(o, OrderedSet) and list(self.the_dict) == list(o.the_dict)
def __ne__(self, o: object) -> bool:
return not self.__eq__(o)
def __str__(self) -> str:
return "{" + ", ".join(list(map(str, self.the_dict))) + "}"
def __repr__(self) -> str:
return f"OrderedSet({repr(self.the_dict)})"
def add(self, element: T) -> None:
self.the_dict = {**self.the_dict, **{element: None}}
def clear(self) -> None:
self.the_dict.clear()
def copy(self) -> 'OrderedSet[T]':
return OrderedSet(self.the_dict.copy())
def difference(self, s: Iterable[Any]) -> 'OrderedSet[T]':
return OrderedSet({e: None for e in self.the_dict if e not in s})
def difference_update(self, s: Iterable[Any]) -> None:
self.the_dict = {e: None for e in self.the_dict if e not in s}
def discard(self, element: T) -> None:
del self.the_dict[element]
def intersection(self, s: Iterable[Any]) -> 'OrderedSet[T]':
return OrderedSet({e: None for e in self.the_dict if e in s})
def intersection_update(self, s: Iterable[Any]) -> None:
self.the_dict = {e: None for e in self.the_dict if e in s}
def isdisjoint(self, s: Iterable[Any]) -> bool:
return self.the_dict.keys().isdisjoint(s)
def issubset(self, s: Iterable[Any]) -> bool:
return set(iter(self)).issubset(iter(s))
def issuperset(self, s: Iterable[Any]) -> bool:
return set(iter(self)).issuperset(iter(s))
def pop(self) -> T:
items = list(self.the_dict)
result = items.pop()
self.the_dict = dict.fromkeys(items)
return result
def remove(self, element: T) -> None:
del self.the_dict[element]
def symmetric_difference(self, s: Iterable[T]) -> 'OrderedSet[T]':
return OrderedSet(
dict.fromkeys([e for e in self.the_dict if e not in s] +
[e for e in s if e not in self.the_dict]))
def symmetric_difference_update(self, s: Iterable[T]) -> None:
self.the_dict = self.symmetric_difference(s).the_dict
def union(self, s: Iterable[T]) -> 'OrderedSet[T]':
return OrderedSet({**self.the_dict, **dict.fromkeys(s)})
def update(self, s: Iterable[T]) -> None:
self.the_dict = self.union(s).the_dict
def __len__(self) -> int:
return len(self.the_dict)
def __contains__(self, o: object) -> bool:
return o in self.the_dict
def __iter__(self) -> Iterator[T]:
return iter(self.the_dict)
def __and__(self, s: AbstractSet[object]) -> 'OrderedSet[T]':
return self.intersection(s)
def __iand__(self, s: AbstractSet[object]) -> 'OrderedSet[T]':
result = self.intersection(s)
self.the_dict = result.the_dict
return result
def __or__(self, s: AbstractSet[S]) -> 'OrderedSet[Union[T, S]]':
return self.union(s)
def __ior__(self, s: AbstractSet[S]) -> 'OrderedSet[Union[T, S]]':
result = self.union(s)
self.the_dict = result.the_dict
return result
def __sub__(self, s: AbstractSet[Optional[T]]) -> 'OrderedSet[T]':
return self.difference(s)
def __isub__(self, s: AbstractSet[Optional[T]]) -> 'OrderedSet[T]':
result = self.difference(s)
self.the_dict = result.the_dict
return result
def __xor__(self, s: AbstractSet[S]) -> 'OrderedSet[Union[T, S]]':
return self.symmetric_difference(s)
def __ixor__(self, s: AbstractSet[S]) -> 'OrderedSet[Union[T, S]]':
result = self.symmetric_difference(s)
self.the_dict = result.the_dict
return result
def __le__(self, s: AbstractSet[object]) -> bool:
return self.issubset(s)
def __lt__(self, s: AbstractSet[object]) -> bool:
return self.issubset(s) and len(self) < len(s)
def __ge__(self, s: AbstractSet[object]) -> bool:
return set(iter(self)) >= set(iter(s))
def __gt__(self, s: AbstractSet[object]) -> bool:
return set(iter(self)) > set(iter(s))

这里有一些示例调用:

>>> from orderedset import OrderedSet
>>> s = OrderedSet([3, 1, 2])
>>> s
OrderedSet({3: None, 1: None, 2: None})
>>> list(s)
[3, 1, 2]
>>> set(s)
set()

有人知道这里发生了什么吗?set()函数似乎是用冗长的C代码实现的,我对这些代码的理解不够好,无法推导出任何内容。然而,似乎__iter__被调用来转换为list,而不是set。。。

有什么想法吗?

非常感谢!

Python3.9或更高版本

您的类应该继承自collections.abc.Set,而不是typing.Set(无论如何都不推荐使用(

from collections.abc import Set
...
class OrderedSet(Generic[T], Set[T]):
...
obj = OrderedSet()
obj.add(1)
obj.add(2)
obj.add(3)
print(set(obj)) # {1,2,3}

Python3.8或更低版本

在3.9之前,将泛型与collections.abc.Set一起使用是不可能的。继承AbstractSet解决了这个问题。

from typing import Generic, AbstractSet
...
class OrderedSet(Generic[T], AbstractSet[T]):
...

您需要初始化super,否则它将是一个空集

def __init__(self, base: Optional[Union[Dict[T, None], Iterable[T]]] = None):
self.the_dict: Dict[T, None]
if not base:
self.the_dict = {}
elif isinstance(base, dict):
self.the_dict = base
else:
self.the_dict = dict.fromkeys(base)
super().__init__(self.the_dict.keys())

最新更新