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