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::
|
|
|
|
|
2018-03-01 03:18:39 +00:00
|
|
|
>>> from collections import ChainMap # (Python 3+) # doctest: +SKIP
|
|
|
|
>>> issubclass(ChainMap, dict) # doctest: +SKIP
|
2018-02-26 23:29:56 +00:00
|
|
|
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-03-01 03:18:39 +00:00
|
|
|
>>> from collections import Mapping # doctest: +SKIP
|
|
|
|
>>> issubclass(ChainMap, Mapping) # doctest: +SKIP
|
2016-06-28 04:05:22 +00:00
|
|
|
True
|
2018-03-01 03:18:39 +00:00
|
|
|
>>> isinstance(bidict(), Mapping) # doctest: +SKIP
|
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.
|
2018-03-01 03:18:39 +00:00
|
|
|
For example, :class:`~bidict.FrozenOrderedBidict` is an immutable mapping
|
2018-02-26 23:29:56 +00:00
|
|
|
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.
|
2018-02-27 13:09:57 +00:00
|
|
|
Have a look through the :mod:`collections.abc` documentation
|
|
|
|
if you're interested.
|
2018-02-26 23:29:56 +00:00
|
|
|
|
2018-02-27 13:09:57 +00:00
|
|
|
One thing you might notice is that there is no
|
|
|
|
``Ordered`` or ``OrderedMapping`` ABC.
|
|
|
|
However, Python 3.6 introduced the :class:`collections.abc.Reversible` ABC.
|
2018-02-26 23:29:56 +00:00
|
|
|
Since being reversible implies having an ordering,
|
2018-02-27 13:09:57 +00:00
|
|
|
you could check for reversibility instead.
|
|
|
|
For example::
|
2018-02-26 23:29:56 +00:00
|
|
|
|
2018-03-01 03:18:39 +00:00
|
|
|
>>> from collections import Reversible # doctest: +SKIP
|
|
|
|
>>> def is_reversible_mapping(cls):
|
|
|
|
... return issubclass(cls, Reversible) and issubclass(cls, Mapping)
|
2018-02-26 23:29:56 +00:00
|
|
|
...
|
|
|
|
|
|
|
|
>>> from bidict import OrderedBidict
|
2018-03-01 03:18:39 +00:00
|
|
|
>>> is_reversible_mapping(OrderedBidict) # doctest: +SKIP
|
2018-02-26 23:29:56 +00:00
|
|
|
True
|
|
|
|
|
|
|
|
>>> from collections import OrderedDict
|
2018-03-01 03:18:39 +00:00
|
|
|
>>> is_ordered_mapping(OrderedDict) # doctest: +SKIP
|
2017-11-20 03:24:08 +00:00
|
|
|
True
|