_abcoll.py 15.1 KB
Newer Older
1 2 3 4 5 6
# Copyright 2007 Google, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement.

"""Abstract Base Classes (ABCs) for collections, according to PEP 3119.

DON'T USE THIS MODULE DIRECTLY!  The classes here should be imported
7
via collections; they are defined here only to alleviate certain
8 9 10 11
bootstrapping issues.  Unit tests are in test_collections.
"""

from abc import ABCMeta, abstractmethod
Benjamin Peterson's avatar
Benjamin Peterson committed
12
import sys
13 14 15 16 17 18 19

__all__ = ["Hashable", "Iterable", "Iterator",
           "Sized", "Container", "Callable",
           "Set", "MutableSet",
           "Mapping", "MutableMapping",
           "MappingView", "KeysView", "ItemsView", "ValuesView",
           "Sequence", "MutableSequence",
20
           "ByteString",
21 22
           ]

23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

### collection related types which are not exposed through builtin ###
## iterators ##
bytes_iterator = type(iter(b''))
bytearray_iterator = type(iter(bytearray()))
#callable_iterator = ???
dict_keyiterator = type(iter({}.keys()))
dict_valueiterator = type(iter({}.values()))
dict_itemiterator = type(iter({}.items()))
list_iterator = type(iter([]))
list_reverseiterator = type(iter(reversed([])))
range_iterator = type(iter(range(0)))
set_iterator = type(iter(set()))
str_iterator = type(iter(""))
tuple_iterator = type(iter(()))
zip_iterator = type(iter(zip()))
## views ##
dict_keys = type({}.keys())
dict_values = type({}.values())
dict_items = type({}.items())
43 44
## misc ##
dict_proxy = type(type.__dict__)
45 46


47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
### ONE-TRICK PONIES ###

class Hashable(metaclass=ABCMeta):

    @abstractmethod
    def __hash__(self):
        return 0

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Hashable:
            for B in C.__mro__:
                if "__hash__" in B.__dict__:
                    if B.__dict__["__hash__"]:
                        return True
                    break
        return NotImplemented


class Iterable(metaclass=ABCMeta):

    @abstractmethod
    def __iter__(self):
        while False:
            yield None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Iterable:
            if any("__iter__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented


Raymond Hettinger's avatar
Raymond Hettinger committed
81
class Iterator(Iterable):
82 83 84 85 86 87 88 89 90 91 92

    @abstractmethod
    def __next__(self):
        raise StopIteration

    def __iter__(self):
        return self

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Iterator:
93 94
            if (any("__next__" in B.__dict__ for B in C.__mro__) and
                any("__iter__" in B.__dict__ for B in C.__mro__)):
95 96 97
                return True
        return NotImplemented

98 99 100 101 102 103 104 105 106 107 108 109 110
Iterator.register(bytes_iterator)
Iterator.register(bytearray_iterator)
#Iterator.register(callable_iterator)
Iterator.register(dict_keyiterator)
Iterator.register(dict_valueiterator)
Iterator.register(dict_itemiterator)
Iterator.register(list_iterator)
Iterator.register(list_reverseiterator)
Iterator.register(range_iterator)
Iterator.register(set_iterator)
Iterator.register(str_iterator)
Iterator.register(tuple_iterator)
Iterator.register(zip_iterator)
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142

class Sized(metaclass=ABCMeta):

    @abstractmethod
    def __len__(self):
        return 0

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Sized:
            if any("__len__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented


class Container(metaclass=ABCMeta):

    @abstractmethod
    def __contains__(self, x):
        return False

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Container:
            if any("__contains__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented


class Callable(metaclass=ABCMeta):

    @abstractmethod
143
    def __call__(self, *args, **kwds):
144 145 146 147 148 149 150 151 152 153 154 155 156
        return False

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Callable:
            if any("__call__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented


### SETS ###


Raymond Hettinger's avatar
Raymond Hettinger committed
157
class Set(Sized, Iterable, Container):
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183

    """A set is a finite, iterable container.

    This class provides concrete generic implementations of all
    methods except for __contains__, __iter__ and __len__.

    To override the comparisons (presumably for speed, as the
    semantics are fixed), all you have to do is redefine __le__ and
    then the other operations will automatically follow suit.
    """

    def __le__(self, other):
        if not isinstance(other, Set):
            return NotImplemented
        if len(self) > len(other):
            return False
        for elem in self:
            if elem not in other:
                return False
        return True

    def __lt__(self, other):
        if not isinstance(other, Set):
            return NotImplemented
        return len(self) < len(other) and self.__le__(other)

184 185 186
    def __gt__(self, other):
        if not isinstance(other, Set):
            return NotImplemented
187
        return other.__lt__(self)
188 189 190 191

    def __ge__(self, other):
        if not isinstance(other, Set):
            return NotImplemented
192
        return other.__le__(self)
193

194 195 196 197 198
    def __eq__(self, other):
        if not isinstance(other, Set):
            return NotImplemented
        return len(self) == len(other) and self.__le__(other)

199 200 201
    def __ne__(self, other):
        return not (self == other)

202 203
    @classmethod
    def _from_iterable(cls, it):
204 205 206
        '''Construct an instance of the class from any iterable input.

        Must override this method if the class constructor signature
207
        does not accept an iterable for an input.
208
        '''
209
        return cls(it)
210 211 212 213 214 215

    def __and__(self, other):
        if not isinstance(other, Iterable):
            return NotImplemented
        return self._from_iterable(value for value in other if value in self)

216 217 218 219 220 221
    def isdisjoint(self, other):
        for value in other:
            if value in self:
                return False
        return True

222 223 224
    def __or__(self, other):
        if not isinstance(other, Iterable):
            return NotImplemented
225 226
        chain = (e for s in (self, other) for e in s)
        return self._from_iterable(chain)
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257

    def __sub__(self, other):
        if not isinstance(other, Set):
            if not isinstance(other, Iterable):
                return NotImplemented
            other = self._from_iterable(other)
        return self._from_iterable(value for value in self
                                   if value not in other)

    def __xor__(self, other):
        if not isinstance(other, Set):
            if not isinstance(other, Iterable):
                return NotImplemented
            other = self._from_iterable(other)
        return (self - other) | (other - self)

    def _hash(self):
        """Compute the hash value of a set.

        Note that we don't define __hash__: not all sets are hashable.
        But if you define a hashable set type, its __hash__ should
        call this function.

        This must be compatible __eq__.

        All sets ought to compare equal if they contain the same
        elements, regardless of how they are implemented, and
        regardless of the order of the elements; so there's not much
        freedom for __eq__ or __hash__.  We match the algorithm used
        by the built-in frozenset type.
        """
258
        MAX = sys.maxsize
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
        MASK = 2 * MAX + 1
        n = len(self)
        h = 1927868237 * (n + 1)
        h &= MASK
        for x in self:
            hx = hash(x)
            h ^= (hx ^ (hx << 16) ^ 89869747)  * 3644798167
            h &= MASK
        h = h * 69069 + 907133923
        h &= MASK
        if h > MAX:
            h -= MASK + 1
        if h == -1:
            h = 590923713
        return h

Set.register(frozenset)


class MutableSet(Set):

    @abstractmethod
    def add(self, value):
Benjamin Peterson's avatar
Benjamin Peterson committed
282
        """Add an element."""
283 284 285 286
        raise NotImplementedError

    @abstractmethod
    def discard(self, value):
Benjamin Peterson's avatar
Benjamin Peterson committed
287
        """Remove an element.  Do not raise an exception if absent."""
288 289
        raise NotImplementedError

290 291 292 293 294 295
    def remove(self, value):
        """Remove an element. If not a member, raise a KeyError."""
        if value not in self:
            raise KeyError(value)
        self.discard(value)

296 297 298 299
    def pop(self):
        """Return the popped value.  Raise KeyError if empty."""
        it = iter(self)
        try:
300
            value = next(it)
301 302 303 304 305 306 307 308 309 310 311 312 313
        except StopIteration:
            raise KeyError
        self.discard(value)
        return value

    def clear(self):
        """This is slow (creates N new iterators!) but effective."""
        try:
            while True:
                self.pop()
        except KeyError:
            pass

314
    def __ior__(self, it):
315 316 317 318
        for value in it:
            self.add(value)
        return self

319
    def __iand__(self, it):
320 321
        for value in (self - it):
            self.discard(value)
322 323
        return self

324
    def __ixor__(self, it):
325 326 327 328 329 330 331 332 333 334
        if it is self:
            self.clear()
        else:
            if not isinstance(it, Set):
                it = self._from_iterable(it)
            for value in it:
                if value in self:
                    self.discard(value)
                else:
                    self.add(value)
335 336
        return self

337
    def __isub__(self, it):
338 339 340 341 342
        if it is self:
            self.clear()
        else:
            for value in it:
                self.discard(value)
343 344 345 346 347 348 349 350
        return self

MutableSet.register(set)


### MAPPINGS ###


Raymond Hettinger's avatar
Raymond Hettinger committed
351
class Mapping(Sized, Iterable, Container):
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379

    @abstractmethod
    def __getitem__(self, key):
        raise KeyError

    def get(self, key, default=None):
        try:
            return self[key]
        except KeyError:
            return default

    def __contains__(self, key):
        try:
            self[key]
        except KeyError:
            return False
        else:
            return True

    def keys(self):
        return KeysView(self)

    def items(self):
        return ItemsView(self)

    def values(self):
        return ValuesView(self)

380
    def __eq__(self, other):
381 382 383
        if not isinstance(other, Mapping):
            return NotImplemented
        return dict(self.items()) == dict(other.items())
384 385

    def __ne__(self, other):
386
        return not (self == other)
387

Christian Heimes's avatar
Christian Heimes committed
388

389
class MappingView(Sized):
390 391 392 393 394 395 396

    def __init__(self, mapping):
        self._mapping = mapping

    def __len__(self):
        return len(self._mapping)

397 398 399
    def __repr__(self):
        return '{0.__class__.__name__}({0._mapping!r})'.format(self)

400 401 402

class KeysView(MappingView, Set):

403 404 405 406
    @classmethod
    def _from_iterable(self, it):
        return set(it)

407 408 409 410 411 412 413
    def __contains__(self, key):
        return key in self._mapping

    def __iter__(self):
        for key in self._mapping:
            yield key

414
KeysView.register(dict_keys)
415 416 417 418


class ItemsView(MappingView, Set):

419 420 421 422
    @classmethod
    def _from_iterable(self, it):
        return set(it)

423 424 425 426 427 428 429 430 431 432 433 434 435
    def __contains__(self, item):
        key, value = item
        try:
            v = self._mapping[key]
        except KeyError:
            return False
        else:
            return v == value

    def __iter__(self):
        for key in self._mapping:
            yield (key, self._mapping[key])

436
ItemsView.register(dict_items)
437 438 439 440 441 442 443 444 445 446 447 448 449 450


class ValuesView(MappingView):

    def __contains__(self, value):
        for key in self._mapping:
            if value == self._mapping[key]:
                return True
        return False

    def __iter__(self):
        for key in self._mapping:
            yield self._mapping[key]

451
ValuesView.register(dict_values)
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492


class MutableMapping(Mapping):

    @abstractmethod
    def __setitem__(self, key, value):
        raise KeyError

    @abstractmethod
    def __delitem__(self, key):
        raise KeyError

    __marker = object()

    def pop(self, key, default=__marker):
        try:
            value = self[key]
        except KeyError:
            if default is self.__marker:
                raise
            return default
        else:
            del self[key]
            return value

    def popitem(self):
        try:
            key = next(iter(self))
        except StopIteration:
            raise KeyError
        value = self[key]
        del self[key]
        return key, value

    def clear(self):
        try:
            while True:
                self.popitem()
        except KeyError:
            pass

493 494 495 496 497 498 499 500 501
    def update(*args, **kwds):
        if len(args) > 2:
            raise TypeError("update() takes at most 2 positional "
                            "arguments ({} given)".format(len(args)))
        elif not args:
            raise TypeError("update() takes at least 1 argument (0 given)")
        self = args[0]
        other = args[1] if len(args) >= 2 else ()

502 503 504 505 506 507 508 509 510 511 512 513
        if isinstance(other, Mapping):
            for key in other:
                self[key] = other[key]
        elif hasattr(other, "keys"):
            for key in other.keys():
                self[key] = other[key]
        else:
            for key, value in other:
                self[key] = value
        for key, value in kwds.items():
            self[key] = value

514 515 516 517 518 519 520
    def setdefault(self, key, default=None):
        try:
            return self[key]
        except KeyError:
            self[key] = default
        return default

521 522 523 524 525 526
MutableMapping.register(dict)


### SEQUENCES ###


Raymond Hettinger's avatar
Raymond Hettinger committed
527
class Sequence(Sized, Iterable, Container):
528 529 530 531 532 533 534 535 536 537 538 539 540

    """All the operations on a read-only sequence.

    Concrete subclasses must override __new__ or __init__,
    __getitem__, and __len__.
    """

    @abstractmethod
    def __getitem__(self, index):
        raise IndexError

    def __iter__(self):
        i = 0
541 542
        try:
            while True:
543
                v = self[i]
544 545 546 547
                yield v
                i += 1
        except IndexError:
            return
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568

    def __contains__(self, value):
        for v in self:
            if v == value:
                return True
        return False

    def __reversed__(self):
        for i in reversed(range(len(self))):
            yield self[i]

    def index(self, value):
        for i, v in enumerate(self):
            if v == value:
                return i
        raise ValueError

    def count(self, value):
        return sum(1 for v in self if v == value)

Sequence.register(tuple)
569
Sequence.register(str)
570
Sequence.register(range)
571 572 573 574 575 576 577 578 579 580 581


class ByteString(Sequence):

    """This unifies bytes and bytearray.

    XXX Should add all their methods.
    """

ByteString.register(bytes)
ByteString.register(bytearray)
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619


class MutableSequence(Sequence):

    @abstractmethod
    def __setitem__(self, index, value):
        raise IndexError

    @abstractmethod
    def __delitem__(self, index):
        raise IndexError

    @abstractmethod
    def insert(self, index, value):
        raise IndexError

    def append(self, value):
        self.insert(len(self), value)

    def reverse(self):
        n = len(self)
        for i in range(n//2):
            self[i], self[n-i-1] = self[n-i-1], self[i]

    def extend(self, values):
        for v in values:
            self.append(v)

    def pop(self, index=-1):
        v = self[index]
        del self[index]
        return v

    def remove(self, value):
        del self[self.index(value)]

    def __iadd__(self, values):
        self.extend(values)
620
        return self
621 622

MutableSequence.register(list)
623
MutableSequence.register(bytearray)  # Multiply inheriting, see ByteString