python bijection

Francis Carr coldtortuga at gmail.com
Thu Dec 3 16:17:02 EST 2009


[In re R. Hettinger's critiques]

> * it extends the language with arcane syntax tricks...
I think most of these in the current version of J. Bronson's "bidict"
can be left unused, or removed altogether.  In almost all cases, a
bidict should be accessed as an ordinary python dict.


> * we've already got one (actually two).
>   The two dictionary approach...
Solutions such as bidict just automate the two-dict approach.

>   ...sqlite3 provides another way...
In many many cases, using a dB (even a lightweight such as sqlite3) is
swatting the fly with a sledgehammer :-)


> Since bijections are symmetrical, they do not have an obvious
> direction (which is the primary key, the husband or the wife?).
I think this is easy to solve with a classmethod constructor that
produces a pair of "linked" dicts.  For example,
  husband2wife, wife2husband = bidict.makepair(('Fred', 'John'),
('Mary', 'Ruth'))
Obviously from the code this pair of bidicts are "linked", and the
direction of each mapping is obvious from its name.  Metaprogramming
idioms like namedtuple are not required.


> * the semantics of a bijection aren't obvious:
>      b['x'] = 'ex'      # first record:  ('x', 'ex')
>      b['y'] = 'why'     # second record: ('y', 'why')
>      b[:'why'] = 'x'    # do two records collapse into one?
>                         # is there an error?
Among the various critiques, I think this is the most significant.

When I was fiddling with my implementation, I was disturbed that the
code
  bidict[newKey] = oldValue
should have the subtle side-effect
  del bidict.inv[oldValue]

And there is a much stranger case.  Suppose bidict[key1]=val1 and
bidict[key2]=val2.  Then the code
  bidict[key1] = val2
should have the extremely subtle side-effects
  del bidict[key2]      # because val2 has been re-mapped
  del bidict.inv[val1]  # because key1 has been re-mapped
Blech!

I think there must be something better.  It would be interesting to
hear more opinions on the matter.

I propose raising ValueError when operating on one key would also
silently re-map or delete a different (key,value) pair.  This would
disallow both of the above cases.  To get the effect of the first
case, one would simply operate on the inverse mapping:
  bidict.inv[oldValue] = newKey
This should not be confusing: it's exactly how a python dict would
operate, except the "linked" mapping is altered to match, which is the
bookkeeping we want to automate in the first place.  To get the effect
of the second case, one would have to explicitly demand the side-
effects:
  del bidict[key2]
  del bidict.inv[val1]
  bidict[key1] = val2
Also not confusing.


 -- FC



More information about the Python-list mailing list