bidict/docs/intro.doctest.rst

109 lines
2.9 KiB
ReStructuredText
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

.. _intro:
Intro
=====
The :mod:`bidict` package provides a
`bidirectional map <https://en.wikipedia.org/wiki/Bidirectional_map>`_
data structure
and related functionality to work with one-to-one mappings in Python,
Pythonically.
bidict.bidict
-------------
:class:`bidict.bidict`
is the main bidirectional map data structure provided.
It implements the familiar API you're used to from dict::
>>> from bidict import bidict
>>> element_by_symbol = bidict(H='hydrogen')
>>> element_by_symbol
bidict({'H': 'hydrogen'})
>>> element_by_symbol['H']
'hydrogen'
But it also maintains the inverse bidict via the
:attr:`inv <bidict.BidirectionalMapping.inv>` attribute::
>>> element_by_symbol.inv
bidict({'hydrogen': 'H'})
>>> element_by_symbol.inv['hydrogen']
'H'
>>> element_by_symbol.inv.inv is element_by_symbol
True
Concise, efficient, Pythonic.
Why Can't I Just Use dict?
--------------------------
A skeptic writes:
If I want a mapping *a* ↔︎ *b*,
I would just create a dict *{a: b, b: a}*.
What is the advantage of bidict
over the simplicity of the dict approach?
Glad you asked.
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
and the rest is taken care of for you.
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.
In other words,
you lose information about which mappings are the forward mappings
and which are the inverse.
*d.keys()* and *d.values()* would each give you
the same 2x-too-big jumble of keys and values
all mixed together,
and *d.items()* would likewise be
the 2x-too-big combination of forward and inverse mappings
all mixed together.
In short,
to model a bidirectional map,
you need two separate one-directional maps
that are kept in sync as the bidirectional map changes.
This is exactly what bidict does under the hood,
abstracting this into a clean and simple interface,
while providing complementary functionality to boot.
Additional Functionality
------------------------
Besides :class:`bidict.bidict`,
the :mod:`bidict` package provides additional tools
for working with one-to-one relations:
- :class:`bidict.frozenbidict`
- :class:`bidict.loosebidict`
- :class:`bidict.orderedbidict`
- :class:`bidict.frozenorderedbidict`
- :class:`bidict.looseorderedbidict`
- :class:`bidict.namedbidict`
- :class:`bidict.inverted`
These will be covered in later sections.
But first let's proceed to :ref:`basic-usage`.