container: allows testing for item membership using in and not insized: allows determining number of items in collection with len(x)iterable: can produce iterator with iter(x) (think for..in loop)sequence: supports random read access to collectionsset: supports various set algebra operations (methods and infix operators)
subset and proper subsetequal and not equalproper superset and supersetintersections and unionsymmetric difference and differencecontainerin and not in__contains__(item)sizedlen(sized) function__len__()iterableiter(iterable) function__iter__()sequencecontainer, sized, and iterable protocolsitem = seq[index]item = seq[start:stop]__getitem__()r = reversed(seq)
__reversed__()__getitem__() and __len__()index = seq.index(item)num = seq.count(item)+ operator
__add__()* operator
__mul__() => when class is on left-hand side of operator__rmul__() => when class is on right-hand side of operatorSequence from collections.abc (see Python docs for more info)Special methods:
- equality => __eq__()
- inequality => __ne__()
setSet from collections.abc (see Python docs for more info)
MutableSet from collections.abc insteadadd() and discard()update() and symmetric_difference_update(), etc.copy method| special method | infix operator | set method |
meaning |
|---|---|---|---|
__le__() |
<= |
issubset() |
subset |
__lt__() |
< |
proper subset | |
__eq__() |
== |
equal | |
__ne__() |
!= |
not equal | |
__gt__() |
> |
proper superset | |
__ge__() |
>= |
issuperset() |
superset |
| special method | infix operator | set method |
|---|---|---|
__and__() |
& |
intersection() |
__or__() |
` | ` |
__xor__() |
^ |
symmetric_difference() |
__sub__() |
- |
symmetric_difference() |
Example: SortedSet which is sized, iterable, sequence container of set of distinct items and constructible from an iterable
# sorted_set.py
from bisect import bisect_left
from collections.abc import Sequence, Set
from itertools import chain
class SortedSet(Sequence, Set):
def __init__(self, items):
self._items = sorted(set(items)) if items is not None else []
def __contains__(self, item):
### before refactor
# return item in self._items
### after refactor
index = bisect_left(self._items, item)
return (index != len(self._items)) and (self._items[index] == item)
def __len__(self):
return len(self._items)
def __iter__(self):
# return iter(self._items)
for item in self._items:
yield item
def __getitem__(self, index):
# return self._items[index]
result = self._items[index]
return SortedSet(result) if isinstance(index, slice) else result
def __repr__(self):
return "SortedSet({})".format(
repr(self._items) if self._items else ''
)
def __eq__(self, right_hand_side):
if not isinstance(right_hand_side, SortedSet):
return NotImplemented
return self._items == right_hand_side._items
def __ne__(self, right_hand_side):
if not isinstance(right_hand_side, SortedSet):
return NotImplemented
return self._items != right_hand_side._items
def index(self, item):
index = bisect_left(self._items, item)
if (index != len(self._items)) and (self._items[index] == item):
return index
raise ValueError("{} not found").format(repr(item))
# Override inherited `count` method to improve performance from O(n) => O(log n)
def count(self, item):
### before refactor
# index = bisect_left(self._items, item)
# found = (index != len(self._items)) and (self._items[index] == item)
# return int(found)
### after refactor
return int(item in self)
def __add__(self, right_hand_side):
return SortedSet(chain(self._items, right_hand_side._items))
def __mul__(self, right_hand_side):
return self if right_hand_side > 0 else SortedSet()
def __rmul__(self, left_hand_side):
return self * left_hand_side
def issubset(self, iterable):
return self <= SortedSet(iterable)
def issuperset(self, iterable):
return self >= SortedSet(iterable)
def interaction(self, iterable):
return self & SortedSet(iterable)
def union(self, iterable):
return self | SortedSet(iterable)
def symmetric_difference(y)(self, iterable):
return self ^ SortedSet(iterable)
def difference(self, iterable):
return self - SortedSet(iterable)
collections.abc