这是一个可能的解决方案:
from collections import Iterable
class AliasDefaultDict():
def __init__(self, default_factory, initial=[]):
self.aliases = {}
self.data = {}
self.factory = default_factory
for aliases, value in initial:
self[aliases] = value
@staticmethod
def distinguish_keys(key):
if isinstance(key, Iterable) and not isinstance(key, str):
return set(key)
else:
return {key}
def __getitem__(self, key):
keys = self.distinguish_keys(key)
if keys & self.aliases.keys():
return self.data[self.aliases[keys.pop()]]
else:
value = self.factory()
self[keys] = value
return value
def __setitem__(self, key, value):
keys = self.distinguish_keys(key)
if keys & self.aliases.keys():
self.data[self.aliases[keys.pop()]] = value
else:
new_key = object()
self.data[new_key] = value
for key in keys:
self.aliases[key] = new_key
return value
def __repr__(self):
representation = defaultdict(list)
for alias, value in self.aliases.items():
representation[value].append(alias)
return "AliasDefaultDict({}, {})".format(repr(self.factory), repr([(aliases, self.data[value]) for value, aliases in representation.items()]))
可以这样使用:
>>> a_dict = AliasDefaultDict(dict)
>>> a_dict['food', 'canned_food']['spam'] = 'delicious'
>>> a_dict['food']
{'spam': 'delicious'}
>>> a_dict['canned_food']
{'spam': 'delicious'}
>> a_dict
AliasDefaultDict(<class 'dict'>, [(['food', 'canned_food'], {'spam': 'delicious'})])
请注意,有些边缘情况具有未定义的行为 - 例如对多个别名使用相同的键。我觉得这使得这种数据类型对于一般用途来说非常糟糕,我建议你最好改变你的程序而不需要这种过于复杂的结构。
str
另请注意,此解决方案适用于 3.x,在 2.x下,您需要换掉basestring
和self.aliases.keys()
。self.aliases.viewkeys()