Defaultdict 自动为每个键创建一个子字典?

Defaultdict that automatically creates a sub-dict for each key?

我有一本字典,我经常在我的代码中做这样的事情:

special_dict = {}

# ...

if username not in special_dict:
    special_dict[username] = {}
    for subkey in ["Subkey1", "Subkey2", "Subkey3"]:
        special_dict[username][subkey] = []  # or {}, etc, depending on usecase

基本上我想要一个字典,其中对于每个用户名,值是另一个包含三个特定子键的字典,然后这些值是列表或集合或者你有什么。

我熟悉 defaultdict,但我不确定如何使这里的“值类型”变得非常具体。通常我会 defaultdict(list) 如果我希望每个值默认都是一个列表,但是有没有办法让默认值不是一个列表而是它本身是一个特定类型的字典?

理想情况下,最终我想要做的是 special_dict[username][subkey].append(item) 而不必首先担心用户名是否存在,因为如果不存在,它将成为键并形成三个子键。

您需要一个函数来创建您想要的结构,并将此函数作为参数传递给 defaultdict:

from collections import defaultdict

def name_subdict():
    return {'key1':[], 'key2':set(), 'key3':{}}

mydict = defaultdict(name_subdict)

mydict['John']['key1'].append(1)
mydict['John']['key2'].add(2)
mydict['Jane']['key3'][10] = 20

print(mydict)
# defaultdict(<function name_subdict at 0x7fcaf81193a0>, 
# {'John': {'key1': [1], 'key2': {2}, 'key3': {}}, 
#  'Jane': {'key1': [], 'key2': set(), 'key3': {10: 20}}})

回答您的评论:是的,您可以传递要用于所有子项的数据类型,如 mydict = name_subdict(list) 中所示。只有一个警告:defaultdict 的参数必须是一个不带参数的函数(或任何可调用函数)。

因此,name_subdict(list) 应该 return 一个将依次创建结构的函数。

代码将是:

from collections import defaultdict

def name_subdict(data_type):
    # data type must be a callable like list, set, dict...
    def subdict_creator():
        return {key:data_type() for key in ['key1', 'key2', 'key3']}
    return subdict_creator
    
my_list_dict = defaultdict(name_subdict(list))
my_set_dict = defaultdict(name_subdict(set))

my_list_dict['John']['key1'].append(1)
my_list_dict['John']['key2'].append(2)

my_set_dict['Jane']['key3'].add(10)

print(my_list_dict)
# defaultdict(<function name_subdict.<locals>.subdict_creator at 0x7fcadbf27b80>, 
# {'John': {'key1': [1], 'key2': [2], 'key3': []}})

print(my_set_dict)
# defaultdict(<function name_subdict.<locals>.subdict_creator at 0x7fcadbbf25e0>, 
# {'Jane': {'key1': set(), 'key2': set(), 'key3': {10}}})