2016-06-28 04:05:22 +00:00
|
|
|
.. _polymorphism:
|
|
|
|
|
|
|
|
Polymorphism
|
|
|
|
------------
|
|
|
|
|
2018-02-26 23:29:56 +00:00
|
|
|
a.k.a "Know your ABCs"
|
|
|
|
|
|
|
|
You may be tempted to write something like ``isinstance(obj, dict)``
|
|
|
|
to check whether ``obj`` is a :class:`~collections.abc.Mapping`.
|
|
|
|
However, this check is too specific, and will fail for many
|
|
|
|
types that implement the :class:`~collections.abc.Mapping` interface::
|
|
|
|
|
|
|
|
>>> from collections import ChainMap
|
|
|
|
>>> issubclass(ChainMap, dict)
|
|
|
|
False
|
|
|
|
|
|
|
|
The same is true for all the bidict types::
|
2016-06-28 04:05:22 +00:00
|
|
|
|
|
|
|
>>> from bidict import bidict
|
2018-02-26 23:29:56 +00:00
|
|
|
>>> issubclass(bidict, dict)
|
2016-06-28 04:05:22 +00:00
|
|
|
False
|
|
|
|
|
2018-02-26 23:29:56 +00:00
|
|
|
The proper way to check whether an object
|
|
|
|
is a :class:`~collections.abc.Mapping`
|
|
|
|
is to use the abstract base classes (ABCs)
|
|
|
|
from the :mod:`collections` module
|
|
|
|
that are provided for this purpose::
|
2016-06-28 04:05:22 +00:00
|
|
|
|
2018-02-26 23:29:56 +00:00
|
|
|
>>> from collections import Mapping
|
|
|
|
>>> issubclass(ChainMap, Mapping)
|
2016-06-28 04:05:22 +00:00
|
|
|
True
|
2018-02-26 23:29:56 +00:00
|
|
|
>>> isinstance(bidict(), Mapping)
|
2016-06-28 04:05:22 +00:00
|
|
|
True
|
|
|
|
|
2018-02-26 23:29:56 +00:00
|
|
|
Also note that the proper way to check whether an object
|
|
|
|
is an (im)mutable mapping is to use the
|
|
|
|
:class:`~collections.abc.MutableMapping` ABC::
|
2016-06-28 04:05:22 +00:00
|
|
|
|
2018-02-26 23:29:56 +00:00
|
|
|
>>> from collections import MutableMapping
|
|
|
|
>>> from bidict import BidirectionalMapping, frozenbidict
|
2017-11-20 03:24:08 +00:00
|
|
|
|
2018-02-26 23:29:56 +00:00
|
|
|
>>> def is_immutable_bimap(obj):
|
|
|
|
... return (isinstance(obj, BidirectionalMapping)
|
|
|
|
... and not isinstance(obj, MutableMapping))
|
2017-11-20 03:24:08 +00:00
|
|
|
|
2018-02-26 23:29:56 +00:00
|
|
|
>>> is_immutable_bimap(bidict())
|
|
|
|
False
|
2017-11-20 03:24:08 +00:00
|
|
|
|
2018-02-26 23:29:56 +00:00
|
|
|
>>> is_immutable_bimap(frozenbidict())
|
2017-11-20 03:24:08 +00:00
|
|
|
True
|
|
|
|
|
2018-02-26 23:29:56 +00:00
|
|
|
Checking for ``isinstance(obj, frozenbidict)`` is too specific
|
|
|
|
and could fail in some cases.
|
|
|
|
Namely, :class:`~bidict.FrozenOrderedBidict` is an immutable mapping
|
|
|
|
but it does not subclass :class:`~bidict.frozenbidict`::
|
|
|
|
|
|
|
|
>>> from bidict import FrozenOrderedBidict
|
|
|
|
>>> obj = FrozenOrderedBidict()
|
|
|
|
>>> is_immutable_bimap(obj)
|
|
|
|
True
|
|
|
|
>>> isinstance(obj, frozenbidict)
|
|
|
|
False
|
|
|
|
|
|
|
|
Besides the above, there are several other collections ABCs
|
|
|
|
whose interfaces are implemented by various bidict types.
|
|
|
|
|
|
|
|
One that may be useful to know about is
|
|
|
|
:class:`collections.abc.Hashable`::
|
2017-11-20 03:24:08 +00:00
|
|
|
|
|
|
|
>>> from collections import Hashable
|
|
|
|
>>> isinstance(frozenbidict(), Hashable)
|
|
|
|
True
|
2018-02-26 23:29:56 +00:00
|
|
|
>>> isinstance(FrozenOrderedBidict(), Hashable)
|
|
|
|
True
|
|
|
|
|
|
|
|
And although there are no ``Ordered`` or ``OrderedMapping`` ABCs,
|
|
|
|
Python 3.6 introduced the :class:`collections.abc.Reversible` ABC.
|
|
|
|
Since being reversible implies having an ordering,
|
|
|
|
you could check for reversibility
|
|
|
|
to generically detect whether a mapping is ordered::
|
|
|
|
|
|
|
|
>>> def is_reversible(cls):
|
|
|
|
... try:
|
|
|
|
... from collections import Reversible
|
|
|
|
... except ImportError: # Python < 3.6
|
|
|
|
... # Better to use a shim of Python 3.6's Reversible, but this'll do for now:
|
|
|
|
... return getattr(cls, '__reversed__', None) is not None
|
|
|
|
... return issubclass(cls, Reversible)
|
|
|
|
|
|
|
|
>>> def is_ordered_mapping(cls):
|
|
|
|
... return is_reversible(cls) and issubclass(cls, Mapping)
|
|
|
|
...
|
|
|
|
|
|
|
|
>>> from bidict import OrderedBidict
|
|
|
|
>>> is_ordered_mapping(OrderedBidict)
|
|
|
|
True
|
|
|
|
|
|
|
|
>>> from collections import OrderedDict
|
|
|
|
>>> is_ordered_mapping(OrderedDict)
|
2017-11-20 03:24:08 +00:00
|
|
|
True
|