转换为自定义集合集 class returns 空集 Python
Conversion to set of custom collections class returns empty set in Python
我最近编写了自己的 OrderedSet 实现,因为我在使用公开可用的 ordered/sorted 集实现时遇到了问题。 class 在后台使用字典代理对象,主要是转发操作。我实施了所有(在我看来)相关的方法,包括。 __iter__
,并且像 list(myset)
这样的调用按预期工作。
但是调用set(myset)
总是returns空集
这是 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
...
有什么想法吗?
非常感谢!
Python 3.9
或以上
您的 class 应该继承自 collections.abc.Set
instead of 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}
Python 3.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())
我最近编写了自己的 OrderedSet 实现,因为我在使用公开可用的 ordered/sorted 集实现时遇到了问题。 class 在后台使用字典代理对象,主要是转发操作。我实施了所有(在我看来)相关的方法,包括。 __iter__
,并且像 list(myset)
这样的调用按预期工作。
但是调用set(myset)
总是returns空集
这是 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
...
有什么想法吗?
非常感谢!
Python 3.9
或以上
您的 class 应该继承自 collections.abc.Set
instead of 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}
Python 3.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())