| 476 | |
| 477 | |
| 478 | class Dict(dict): |
| 479 | def __init__(self, encoder=None): |
| 480 | """ |
| 481 | A dictionary subclass which returns the key value if it is not in the |
| 482 | dict. |
| 483 | |
| 484 | Parameters |
| 485 | ---------- |
| 486 | encoder : function or None |
| 487 | A function which is applied to a key before adding / retrieving it |
| 488 | from the dictionary. If None, the function defaults to the |
| 489 | identity. Default is None. |
| 490 | """ |
| 491 | super(Dict, self).__init__() |
| 492 | self._encoder = encoder |
| 493 | self._id_max = 0 |
| 494 | |
| 495 | def __setitem__(self, key, value): |
| 496 | if self._encoder is not None: |
| 497 | key = self._encoder(key) |
| 498 | elif not isinstance(key, Hashable): |
| 499 | key = tuple(key) |
| 500 | super(Dict, self).__setitem__(key, value) |
| 501 | |
| 502 | def _encode_key(self, key): |
| 503 | D = super(Dict, self) |
| 504 | enc_key = self._encoder(key) |
| 505 | if D.__contains__(enc_key): |
| 506 | val = D.__getitem__(enc_key) |
| 507 | else: |
| 508 | val = self._id_max |
| 509 | D.__setitem__(enc_key, val) |
| 510 | self._id_max += 1 |
| 511 | return val |
| 512 | |
| 513 | def __getitem__(self, key): |
| 514 | self._key = copy.deepcopy(key) |
| 515 | if self._encoder is not None: |
| 516 | return self._encode_key(key) |
| 517 | elif not isinstance(key, Hashable): |
| 518 | key = tuple(key) |
| 519 | return super(Dict, self).__getitem__(key) |
| 520 | |
| 521 | def __missing__(self, key): |
| 522 | return self._key |