这不是一个容易解决的问题,因为在您的示例中:
my_dict[1][2] = 3
my_dict[1]导致__getitem__对字典的调用。那时没有办法知道正在分配任务。只有[]序列中的最后一个是__setitem__调用,除非存在,否则它不会成功mydict[1],因为否则,你分配给什么对象?
所以不要使用自动复活。您可以改用setdefault()常规的dict.
my_dict.setdefault(1, {})[2] = 3
现在这并不完全漂亮,尤其是当您嵌套更深时,因此您可以编写一个辅助方法:
class MyDict(dict):
def nest(self, keys, value):
for key in keys[:-1]:
self = self.setdefault(key, {})
self[keys[-1]] = value
my_dict = MyDict()
my_dict.nest((1, 2), 3) # my_dict[1][2] = 3
但更好的方法是将其包装成一个新__setitem__的,一次获取所有索引,而不是需要诱导自动激活的中间__getitem__调用。这样,我们从一开始就知道我们正在执行一项任务,并且可以在不依赖 autovivication 的情况下继续进行。
class MyDict(dict):
def __setitem__(self, keys, value):
if not isinstance(keys, tuple):
return dict.__setitem__(self, keys, value)
for key in keys[:-1]:
self = self.setdefault(key, {})
dict.__setitem__(self, keys[-1], value)
my_dict = MyDict()
my_dict[1, 2] = 3
为了保持一致性,您还可以提供__getitem__接受元组中的键,如下所示:
def __getitem__(self, keys):
if not isinstance(keys, tuple):
return dict.__getitem__(self, keys)
for key in keys:
self = dict.__getitem__(self, key)
return self
我能想到的唯一缺点是我们不能轻松地将元组用作字典键:我们必须将其写为,例如my_dict[(1, 2),].