This is workable, if you enclose them in a class that checks the constraints, that is
from ZODB.PersistentMapping import PersistentMapping (for example)
class Bidict(Persistent):
def __init__(self):
self._forward = PersistentMapping()
self._reverse = PersistentMapping()
def add(self, from, to):
self._forward[from] = to
self._reverse[to] = from
def getFrom(...)
def getTo(...)
If there's only one way to add data (not deliberately breaking the abstraction), you have reasonnable insurance that your data stays consistent.