blob: d91c0107afc8bc2b97313d3234aa4498d3ca3e36 [file] [log] [blame]
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001# Copyright 2007 Google, Inc. All Rights Reserved.
2# Licensed to PSF under a Contributor Agreement.
3
4"""Abstract Base Classes (ABCs) for collections, according to PEP 3119.
5
6DON'T USE THIS MODULE DIRECTLY! The classes here should be imported
Guido van Rossum7eaf8222007-06-18 17:58:50 +00007via collections; they are defined here only to alleviate certain
Guido van Rossumcd16bf62007-06-13 18:07:49 +00008bootstrapping issues. Unit tests are in test_collections.
9"""
10
11from abc import ABCMeta, abstractmethod
12
13__all__ = ["Hashable", "Iterable", "Iterator",
14 "Sized", "Container", "Callable",
15 "Set", "MutableSet",
16 "Mapping", "MutableMapping",
17 "MappingView", "KeysView", "ItemsView", "ValuesView",
18 "Sequence", "MutableSequence",
Guido van Rossumd05eb002007-11-21 22:26:24 +000019 "ByteString",
Christian Heimesf83be4e2007-11-28 09:44:38 +000020 "bytearray_iterator", "bytes_iterator", "dict_itemiterator",
21 "dict_items", "dict_keyiterator", "dict_keys",
22 "dict_valueiterator", "dict_values", "list_iterator",
23 "list_reverseiterator", "range_iterator", "set_iterator",
24 "str_iterator", "tuple_iterator", "zip_iterator",
Guido van Rossumcd16bf62007-06-13 18:07:49 +000025 ]
26
Christian Heimesf83be4e2007-11-28 09:44:38 +000027
28### collection related types which are not exposed through builtin ###
29## iterators ##
30bytes_iterator = type(iter(b''))
31bytearray_iterator = type(iter(bytearray()))
32#callable_iterator = ???
33dict_keyiterator = type(iter({}.keys()))
34dict_valueiterator = type(iter({}.values()))
35dict_itemiterator = type(iter({}.items()))
36list_iterator = type(iter([]))
37list_reverseiterator = type(iter(reversed([])))
38range_iterator = type(iter(range(0)))
39set_iterator = type(iter(set()))
40str_iterator = type(iter(""))
41tuple_iterator = type(iter(()))
42zip_iterator = type(iter(zip()))
43## views ##
44dict_keys = type({}.keys())
45dict_values = type({}.values())
46dict_items = type({}.items())
47
48
Guido van Rossumcd16bf62007-06-13 18:07:49 +000049### ONE-TRICK PONIES ###
50
51class Hashable(metaclass=ABCMeta):
52
53 @abstractmethod
54 def __hash__(self):
55 return 0
56
57 @classmethod
58 def __subclasshook__(cls, C):
59 if cls is Hashable:
60 for B in C.__mro__:
61 if "__hash__" in B.__dict__:
62 if B.__dict__["__hash__"]:
63 return True
64 break
65 return NotImplemented
66
67
68class Iterable(metaclass=ABCMeta):
69
70 @abstractmethod
71 def __iter__(self):
72 while False:
73 yield None
74
75 @classmethod
76 def __subclasshook__(cls, C):
77 if cls is Iterable:
78 if any("__iter__" in B.__dict__ for B in C.__mro__):
79 return True
80 return NotImplemented
81
Guido van Rossumcd16bf62007-06-13 18:07:49 +000082
83class Iterator(metaclass=ABCMeta):
84
85 @abstractmethod
86 def __next__(self):
87 raise StopIteration
88
89 def __iter__(self):
90 return self
91
92 @classmethod
93 def __subclasshook__(cls, C):
94 if cls is Iterator:
95 if any("__next__" in B.__dict__ for B in C.__mro__):
96 return True
97 return NotImplemented
98
Christian Heimesf83be4e2007-11-28 09:44:38 +000099Iterator.register(bytes_iterator)
100Iterator.register(bytearray_iterator)
101#Iterator.register(callable_iterator)
102Iterator.register(dict_keyiterator)
103Iterator.register(dict_valueiterator)
104Iterator.register(dict_itemiterator)
105Iterator.register(list_iterator)
106Iterator.register(list_reverseiterator)
107Iterator.register(range_iterator)
108Iterator.register(set_iterator)
109Iterator.register(str_iterator)
110Iterator.register(tuple_iterator)
111Iterator.register(zip_iterator)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000112
113class Sized(metaclass=ABCMeta):
114
115 @abstractmethod
116 def __len__(self):
117 return 0
118
119 @classmethod
120 def __subclasshook__(cls, C):
121 if cls is Sized:
122 if any("__len__" in B.__dict__ for B in C.__mro__):
123 return True
124 return NotImplemented
125
126
127class Container(metaclass=ABCMeta):
128
129 @abstractmethod
130 def __contains__(self, x):
131 return False
132
133 @classmethod
134 def __subclasshook__(cls, C):
135 if cls is Container:
136 if any("__contains__" in B.__dict__ for B in C.__mro__):
137 return True
138 return NotImplemented
139
140
141class Callable(metaclass=ABCMeta):
142
143 @abstractmethod
144 def __contains__(self, x):
145 return False
146
147 @classmethod
148 def __subclasshook__(cls, C):
149 if cls is Callable:
150 if any("__call__" in B.__dict__ for B in C.__mro__):
151 return True
152 return NotImplemented
153
154
155### SETS ###
156
157
158class Set(metaclass=ABCMeta):
159
160 """A set is a finite, iterable container.
161
162 This class provides concrete generic implementations of all
163 methods except for __contains__, __iter__ and __len__.
164
165 To override the comparisons (presumably for speed, as the
166 semantics are fixed), all you have to do is redefine __le__ and
167 then the other operations will automatically follow suit.
168 """
169
170 @abstractmethod
171 def __contains__(self, value):
172 return False
173
174 @abstractmethod
175 def __iter__(self):
176 while False:
177 yield None
178
179 @abstractmethod
180 def __len__(self):
181 return 0
182
183 def __le__(self, other):
184 if not isinstance(other, Set):
185 return NotImplemented
186 if len(self) > len(other):
187 return False
188 for elem in self:
189 if elem not in other:
190 return False
191 return True
192
193 def __lt__(self, other):
194 if not isinstance(other, Set):
195 return NotImplemented
196 return len(self) < len(other) and self.__le__(other)
197
198 def __eq__(self, other):
199 if not isinstance(other, Set):
200 return NotImplemented
201 return len(self) == len(other) and self.__le__(other)
202
203 @classmethod
204 def _from_iterable(cls, it):
205 return frozenset(it)
206
207 def __and__(self, other):
208 if not isinstance(other, Iterable):
209 return NotImplemented
210 return self._from_iterable(value for value in other if value in self)
211
212 def __or__(self, other):
213 if not isinstance(other, Iterable):
214 return NotImplemented
215 return self._from_iterable(itertools.chain(self, other))
216
217 def __sub__(self, other):
218 if not isinstance(other, Set):
219 if not isinstance(other, Iterable):
220 return NotImplemented
221 other = self._from_iterable(other)
222 return self._from_iterable(value for value in self
223 if value not in other)
224
225 def __xor__(self, other):
226 if not isinstance(other, Set):
227 if not isinstance(other, Iterable):
228 return NotImplemented
229 other = self._from_iterable(other)
230 return (self - other) | (other - self)
231
232 def _hash(self):
233 """Compute the hash value of a set.
234
235 Note that we don't define __hash__: not all sets are hashable.
236 But if you define a hashable set type, its __hash__ should
237 call this function.
238
239 This must be compatible __eq__.
240
241 All sets ought to compare equal if they contain the same
242 elements, regardless of how they are implemented, and
243 regardless of the order of the elements; so there's not much
244 freedom for __eq__ or __hash__. We match the algorithm used
245 by the built-in frozenset type.
246 """
247 MAX = sys.maxint
248 MASK = 2 * MAX + 1
249 n = len(self)
250 h = 1927868237 * (n + 1)
251 h &= MASK
252 for x in self:
253 hx = hash(x)
254 h ^= (hx ^ (hx << 16) ^ 89869747) * 3644798167
255 h &= MASK
256 h = h * 69069 + 907133923
257 h &= MASK
258 if h > MAX:
259 h -= MASK + 1
260 if h == -1:
261 h = 590923713
262 return h
263
264Set.register(frozenset)
265
266
267class MutableSet(Set):
268
269 @abstractmethod
270 def add(self, value):
271 """Return True if it was added, False if already there."""
272 raise NotImplementedError
273
274 @abstractmethod
275 def discard(self, value):
276 """Return True if it was deleted, False if not there."""
277 raise NotImplementedError
278
279 def pop(self):
280 """Return the popped value. Raise KeyError if empty."""
281 it = iter(self)
282 try:
283 value = it.__next__()
284 except StopIteration:
285 raise KeyError
286 self.discard(value)
287 return value
288
289 def toggle(self, value):
290 """Return True if it was added, False if deleted."""
291 # XXX This implementation is not thread-safe
292 if value in self:
293 self.discard(value)
294 return False
295 else:
296 self.add(value)
297 return True
298
299 def clear(self):
300 """This is slow (creates N new iterators!) but effective."""
301 try:
302 while True:
303 self.pop()
304 except KeyError:
305 pass
306
307 def __ior__(self, it: Iterable):
308 for value in it:
309 self.add(value)
310 return self
311
312 def __iand__(self, c: Container):
313 for value in self:
314 if value not in c:
315 self.discard(value)
316 return self
317
318 def __ixor__(self, it: Iterable):
319 # This calls toggle(), so if that is overridded, we call the override
320 for value in it:
321 self.toggle(it)
322 return self
323
324 def __isub__(self, it: Iterable):
325 for value in it:
326 self.discard(value)
327 return self
328
329MutableSet.register(set)
330
331
332### MAPPINGS ###
333
334
335class Mapping(metaclass=ABCMeta):
336
337 @abstractmethod
338 def __getitem__(self, key):
339 raise KeyError
340
341 def get(self, key, default=None):
342 try:
343 return self[key]
344 except KeyError:
345 return default
346
347 def __contains__(self, key):
348 try:
349 self[key]
350 except KeyError:
351 return False
352 else:
353 return True
354
355 @abstractmethod
356 def __len__(self):
357 return 0
358
359 @abstractmethod
360 def __iter__(self):
361 while False:
362 yield None
363
364 def keys(self):
365 return KeysView(self)
366
367 def items(self):
368 return ItemsView(self)
369
370 def values(self):
371 return ValuesView(self)
372
373
374class MappingView(metaclass=ABCMeta):
375
376 def __init__(self, mapping):
377 self._mapping = mapping
378
379 def __len__(self):
380 return len(self._mapping)
381
382
383class KeysView(MappingView, Set):
384
385 def __contains__(self, key):
386 return key in self._mapping
387
388 def __iter__(self):
389 for key in self._mapping:
390 yield key
391
Christian Heimesf83be4e2007-11-28 09:44:38 +0000392KeysView.register(dict_keys)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000393
394
395class ItemsView(MappingView, Set):
396
397 def __contains__(self, item):
398 key, value = item
399 try:
400 v = self._mapping[key]
401 except KeyError:
402 return False
403 else:
404 return v == value
405
406 def __iter__(self):
407 for key in self._mapping:
408 yield (key, self._mapping[key])
409
Christian Heimesf83be4e2007-11-28 09:44:38 +0000410ItemsView.register(dict_items)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000411
412
413class ValuesView(MappingView):
414
415 def __contains__(self, value):
416 for key in self._mapping:
417 if value == self._mapping[key]:
418 return True
419 return False
420
421 def __iter__(self):
422 for key in self._mapping:
423 yield self._mapping[key]
424
Christian Heimesf83be4e2007-11-28 09:44:38 +0000425ValuesView.register(dict_values)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000426
427
428class MutableMapping(Mapping):
429
430 @abstractmethod
431 def __setitem__(self, key, value):
432 raise KeyError
433
434 @abstractmethod
435 def __delitem__(self, key):
436 raise KeyError
437
438 __marker = object()
439
440 def pop(self, key, default=__marker):
441 try:
442 value = self[key]
443 except KeyError:
444 if default is self.__marker:
445 raise
446 return default
447 else:
448 del self[key]
449 return value
450
451 def popitem(self):
452 try:
453 key = next(iter(self))
454 except StopIteration:
455 raise KeyError
456 value = self[key]
457 del self[key]
458 return key, value
459
460 def clear(self):
461 try:
462 while True:
463 self.popitem()
464 except KeyError:
465 pass
466
467 def update(self, other=(), **kwds):
468 if isinstance(other, Mapping):
469 for key in other:
470 self[key] = other[key]
471 elif hasattr(other, "keys"):
472 for key in other.keys():
473 self[key] = other[key]
474 else:
475 for key, value in other:
476 self[key] = value
477 for key, value in kwds.items():
478 self[key] = value
479
480MutableMapping.register(dict)
481
482
483### SEQUENCES ###
484
485
486class Sequence(metaclass=ABCMeta):
487
488 """All the operations on a read-only sequence.
489
490 Concrete subclasses must override __new__ or __init__,
491 __getitem__, and __len__.
492 """
493
494 @abstractmethod
495 def __getitem__(self, index):
496 raise IndexError
497
498 @abstractmethod
499 def __len__(self):
500 return 0
501
502 def __iter__(self):
503 i = 0
504 while True:
505 try:
506 v = self[i]
507 except IndexError:
508 break
509 yield v
510 i += 1
511
512 def __contains__(self, value):
513 for v in self:
514 if v == value:
515 return True
516 return False
517
518 def __reversed__(self):
519 for i in reversed(range(len(self))):
520 yield self[i]
521
522 def index(self, value):
523 for i, v in enumerate(self):
524 if v == value:
525 return i
526 raise ValueError
527
528 def count(self, value):
529 return sum(1 for v in self if v == value)
530
531Sequence.register(tuple)
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000532Sequence.register(str)
Guido van Rossumd05eb002007-11-21 22:26:24 +0000533
534
535class ByteString(Sequence):
536
537 """This unifies bytes and bytearray.
538
539 XXX Should add all their methods.
540 """
541
542ByteString.register(bytes)
543ByteString.register(bytearray)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000544
545
546class MutableSequence(Sequence):
547
548 @abstractmethod
549 def __setitem__(self, index, value):
550 raise IndexError
551
552 @abstractmethod
553 def __delitem__(self, index):
554 raise IndexError
555
556 @abstractmethod
557 def insert(self, index, value):
558 raise IndexError
559
560 def append(self, value):
561 self.insert(len(self), value)
562
563 def reverse(self):
564 n = len(self)
565 for i in range(n//2):
566 self[i], self[n-i-1] = self[n-i-1], self[i]
567
568 def extend(self, values):
569 for v in values:
570 self.append(v)
571
572 def pop(self, index=-1):
573 v = self[index]
574 del self[index]
575 return v
576
577 def remove(self, value):
578 del self[self.index(value)]
579
580 def __iadd__(self, values):
581 self.extend(values)
582
583MutableSequence.register(list)
Guido van Rossumd05eb002007-11-21 22:26:24 +0000584MutableSequence.register(bytearray) # Multiply inheriting, see ByteString