The bidict package provides a Pythonic bidirectional map implementation and related functionality to work with one-to-one mappings in Python.


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']

But it also maintains the inverse bidict via the inv attribute:

>>> element_by_symbol.inv
bidict({'hydrogen': 'H'})
>>> element_by_symbol.inv['hydrogen']
>>> element_by_symbol.inv.inv is element_by_symbol

Concise, efficient, Pythonic.

Why Can’t I Just Use A 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  
>>> d[c] = a  
>>> del d[b]  

With bidicit, you can instead just write:

>>> d[a] = c  

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. 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.

Additional Functionality

Besides the standard bidict.bidict class, the bidict package provides other bidict variants, as well as additional tools for working with one-to-one relations:

These and other provided functionality are covered in later sections.

But first let’s proceed to Basic Usage.