_frozenordered.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2018 Joshua Bronson. All Rights Reserved.
  3. #
  4. # This Source Code Form is subject to the terms of the Mozilla Public
  5. # License, v. 2.0. If a copy of the MPL was not distributed with this
  6. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  7. #==============================================================================
  8. # * Welcome to the bidict source code *
  9. #==============================================================================
  10. # Doing a code review? You'll find a "Code review nav" comment like the one
  11. # below at the top and bottom of the most important source files. This provides
  12. # a suggested initial path through the source when reviewing.
  13. #
  14. # Note: If you aren't reading this on https://github.com/jab/bidict, you may be
  15. # viewing an outdated version of the code. Please head to GitHub to review the
  16. # latest version, which contains important improvements over older versions.
  17. #
  18. # Thank you for reading and for any feedback you provide.
  19. # * Code review nav *
  20. #==============================================================================
  21. #← Prev: _orderedbase.py Current: _frozenordered.py Next: _orderedbidict.py →
  22. #==============================================================================
  23. """Provides :class:`FrozenOrderedBidict`, an immutable, hashable, ordered bidict."""
  24. from ._frozenbidict import frozenbidict
  25. from ._orderedbase import OrderedBidictBase
  26. from ._proxied import _ProxiedKeysVals
  27. from .compat import DICTS_ORDERED, PY2, izip
  28. # FrozenOrderedBidict intentionally does not subclass frozenbidict because it only complicates the
  29. # inheritance hierarchy without providing any actual code reuse: The only thing from frozenbidict
  30. # that FrozenOrderedBidict uses is frozenbidict.__hash__(), but Python specifically prevents
  31. # __hash__ from being inherited; it must instead always be defined explicitly as below. Users who
  32. # need an `is_frozenbidict(..)` test that succeeds for both frozenbidicts and FrozenOrderedBidicts
  33. # should therefore not use isinstance(foo, frozenbidict), but should instead use the appropriate
  34. # ABCs, e.g. `isinstance(foo, BidirectionalMapping) and not isinstance(foo, MutableMapping)`.
  35. class FrozenOrderedBidict(OrderedBidictBase):
  36. """Hashable, immutable, ordered bidict type."""
  37. __slots__ = ()
  38. # frozenbidict.__hash__ can be resued for FrozenOrderedBidict:
  39. # FrozenOrderedBidict inherits BidictBase.__eq__ which is order-insensitive,
  40. # and frozenbidict.__hash__ is consistent with BidictBase.__eq__.
  41. __hash__ = frozenbidict.__hash__ # Must define __hash__ explicitly, Python prevents inheriting
  42. if PY2:
  43. # Must grab the __func__ attribute off the method in Python 2, or else get "TypeError:
  44. # unbound method __hash__() must be called with frozenbidict instance as first argument"
  45. __hash__ = __hash__.__func__
  46. if DICTS_ORDERED:
  47. # If the Python implementation's dict type is ordered (e.g. PyPy or CPython >= 3.6), then
  48. # `FrozenOrderedBidict` can use the `_ProxiedKeysVals` mixin's more efficient implementations
  49. # of `keys` and `values`, rather than the less efficient implementations inherited from
  50. # `Mapping.keys` and `OrderedBidictBase.values`.
  51. # Both the `_fwdm` and `_invm` backing dicts will always be initialized with the provided
  52. # items in the correct order, and since `FrozenOrderedBidict` is immutable, their respective
  53. # orders can't get out of sync after a mutation, like they can with a mutable `OrderedBidict`.
  54. # (`FrozenOrderedBidict` can't use the more efficient `_ProxiedKeysValsItems.items`
  55. # implementation because the values in `_fwdm.items()` are nodes, so inheriting the
  56. # implementation from `Mapping.items` is the best we can do.)
  57. FrozenOrderedBidict.__bases__ = (_ProxiedKeysVals,) + FrozenOrderedBidict.__bases__
  58. if PY2:
  59. # We can do better than the `iteritems` implementation inherited from `Mapping`;
  60. # zipping together the keys from `_fwdm` and `_invm` runs faster (e.g. C speed on CPython).
  61. def iteritems(self):
  62. """An iterator over the contained items."""
  63. return izip(self._fwdm, self._invm) # pylint: disable=protected-access
  64. FrozenOrderedBidict.iteritems = iteritems
  65. # * Code review nav *
  66. #==============================================================================
  67. #← Prev: _orderedbase.py Current: _frozenordered.py Next: _orderedbidict.py →
  68. #==============================================================================