考えられる解決策は次のとおりです。
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()
。