2015-03-22 18:21:15 +00:00
|
|
|
|
.. _intro:
|
|
|
|
|
|
2016-06-28 04:05:22 +00:00
|
|
|
|
Introduction
|
|
|
|
|
============
|
2015-03-22 18:21:15 +00:00
|
|
|
|
|
2016-06-28 04:05:22 +00:00
|
|
|
|
The :mod:`bidict` package provides a Pythonic
|
2015-03-22 18:21:15 +00:00
|
|
|
|
`bidirectional map <https://en.wikipedia.org/wiki/Bidirectional_map>`_
|
2016-06-28 04:05:22 +00:00
|
|
|
|
implementation
|
|
|
|
|
and related functionality to work with one-to-one mappings in Python.
|
2015-03-22 18:21:15 +00:00
|
|
|
|
|
|
|
|
|
bidict.bidict
|
|
|
|
|
-------------
|
|
|
|
|
|
|
|
|
|
:class:`bidict.bidict`
|
|
|
|
|
is the main bidirectional map data structure provided.
|
2015-11-25 22:52:52 +00:00
|
|
|
|
It implements the familiar API you're used to from dict::
|
2015-03-22 18:21:15 +00:00
|
|
|
|
|
2015-12-21 03:05:20 +00:00
|
|
|
|
>>> from bidict import bidict
|
2015-03-22 18:21:15 +00:00
|
|
|
|
>>> element_by_symbol = bidict(H='hydrogen')
|
2015-11-25 22:52:52 +00:00
|
|
|
|
>>> element_by_symbol
|
|
|
|
|
bidict({'H': 'hydrogen'})
|
2015-12-21 03:05:20 +00:00
|
|
|
|
>>> element_by_symbol['H']
|
|
|
|
|
'hydrogen'
|
2015-03-22 18:21:15 +00:00
|
|
|
|
|
2015-12-21 03:05:20 +00:00
|
|
|
|
But it also maintains the inverse bidict via the
|
|
|
|
|
:attr:`inv <bidict.BidirectionalMapping.inv>` attribute::
|
2015-03-22 18:21:15 +00:00
|
|
|
|
|
|
|
|
|
>>> element_by_symbol.inv
|
|
|
|
|
bidict({'hydrogen': 'H'})
|
2015-04-27 22:20:03 +00:00
|
|
|
|
>>> element_by_symbol.inv['hydrogen']
|
|
|
|
|
'H'
|
2015-03-22 18:21:15 +00:00
|
|
|
|
>>> element_by_symbol.inv.inv is element_by_symbol
|
|
|
|
|
True
|
|
|
|
|
|
2015-11-25 22:52:52 +00:00
|
|
|
|
Concise, efficient, Pythonic.
|
|
|
|
|
|
|
|
|
|
|
2016-06-28 04:05:22 +00:00
|
|
|
|
Why Can't I Just Use A dict?
|
|
|
|
|
----------------------------
|
2015-04-27 22:20:03 +00:00
|
|
|
|
|
|
|
|
|
A skeptic writes:
|
|
|
|
|
|
2015-12-21 03:05:20 +00:00
|
|
|
|
If I want a mapping *a* ↔︎ *b*,
|
2016-06-28 04:05:22 +00:00
|
|
|
|
I would just create a dict ``{a: b, b: a}``.
|
2015-04-27 22:20:03 +00:00
|
|
|
|
What is the advantage of bidict
|
|
|
|
|
over the simplicity of the dict approach?
|
|
|
|
|
|
|
|
|
|
Glad you asked.
|
|
|
|
|
|
2015-12-21 03:05:20 +00:00
|
|
|
|
For one, you don't have to manually update the mapping *b* → *a*
|
|
|
|
|
whenever the mapping *a* → *b* changes.
|
|
|
|
|
With the skeptic's method,
|
|
|
|
|
if *a* → *b* needs to change to *a* → *c*,
|
|
|
|
|
you have to write::
|
|
|
|
|
|
|
|
|
|
>>> d[a] = c # doctest: +SKIP
|
|
|
|
|
>>> d[c] = a # doctest: +SKIP
|
|
|
|
|
>>> del d[b] # doctest: +SKIP
|
|
|
|
|
|
|
|
|
|
With bidicit, you can instead just write::
|
|
|
|
|
|
|
|
|
|
>>> d[a] = c # doctest: +SKIP
|
2015-04-27 22:20:03 +00:00
|
|
|
|
|
2015-12-21 03:05:20 +00:00
|
|
|
|
and the rest is taken care of for you.
|
2015-04-27 22:20:03 +00:00
|
|
|
|
|
2015-12-21 03:05:20 +00:00
|
|
|
|
But even more important,
|
|
|
|
|
since the dict approach
|
|
|
|
|
inserts values as keys into the same one-directional map it inserts keys into,
|
|
|
|
|
it's not a bidirectional map so much as
|
|
|
|
|
the destructive merge of two one-directional maps into one.
|
2015-04-27 22:20:03 +00:00
|
|
|
|
|
|
|
|
|
In other words,
|
|
|
|
|
you lose information about which mappings are the forward mappings
|
|
|
|
|
and which are the inverse.
|
2016-06-28 04:05:22 +00:00
|
|
|
|
``d.keys()`` and ``d.values()`` would each give you
|
2015-12-21 03:05:20 +00:00
|
|
|
|
the same 2x-too-big jumble of keys and values
|
|
|
|
|
all mixed together,
|
2016-06-28 04:05:22 +00:00
|
|
|
|
and ``d.items()`` would likewise be
|
2015-12-21 03:05:20 +00:00
|
|
|
|
the 2x-too-big combination of forward and inverse mappings
|
|
|
|
|
all mixed together.
|
2015-04-27 22:20:03 +00:00
|
|
|
|
|
|
|
|
|
In short,
|
|
|
|
|
to model a bidirectional map,
|
2015-12-21 03:05:20 +00:00
|
|
|
|
you need two separate one-directional maps
|
2015-04-27 22:20:03 +00:00
|
|
|
|
that are kept in sync as the bidirectional map changes.
|
2015-12-21 03:05:20 +00:00
|
|
|
|
This is exactly what bidict does under the hood,
|
2016-06-28 04:05:22 +00:00
|
|
|
|
abstracting this into a clean and simple interface.
|
|
|
|
|
bidict also provides rich and powerful facilities
|
|
|
|
|
to help you handle the enforcement of the one-to-one constraint
|
|
|
|
|
(for example, when attempting to set a new key to an existing value)
|
|
|
|
|
exactly as you intend.
|
2015-04-27 22:20:03 +00:00
|
|
|
|
|
2015-03-22 18:21:15 +00:00
|
|
|
|
Additional Functionality
|
|
|
|
|
------------------------
|
|
|
|
|
|
2016-06-28 04:05:22 +00:00
|
|
|
|
Besides the standard :class:`bidict.bidict` class,
|
|
|
|
|
the :mod:`bidict` package provides other bidict variants,
|
|
|
|
|
as well as additional tools
|
2015-03-22 18:21:15 +00:00
|
|
|
|
for working with one-to-one relations:
|
|
|
|
|
|
|
|
|
|
- :class:`bidict.frozenbidict`
|
2015-12-21 03:05:20 +00:00
|
|
|
|
- :class:`bidict.loosebidict`
|
2015-12-25 19:13:02 +00:00
|
|
|
|
- :class:`bidict.orderedbidict`
|
|
|
|
|
- :class:`bidict.namedbidict`
|
2015-03-22 18:21:15 +00:00
|
|
|
|
- :class:`bidict.inverted`
|
2016-06-28 04:05:22 +00:00
|
|
|
|
- :class:`bidict.pairs`
|
2015-03-22 18:21:15 +00:00
|
|
|
|
|
2016-06-28 04:05:22 +00:00
|
|
|
|
These and other provided functionality are covered in later sections.
|
2015-03-22 18:21:15 +00:00
|
|
|
|
|
|
|
|
|
But first let's proceed to :ref:`basic-usage`.
|