在嵌套字典中向内部字典添加新元素

时间:2020-10-16 03:41:03

标签: python dictionary

我正在使用Python 3.6.4。我正在尝试创建由多个进程共享的嵌套字典,并根据各种函数的结果将键值对添加到内部字典中。

下面是我的代码示例。

manager = Manager()
scores = manager.dict()

def add_scores(name, game):
    global scores
    if name not in scores:
        scores[name] = {}
    if game in scores[name]:
        scores[name][game] += 1
    else:
        scores[name] = {game: 1}

填充的字典的示例如下

scores = { 'John': {'golf': '1', 'football': '2'}, 
           'Alice': {'basketball': '1', 'football': '3', 'tennis': 2}}

各种游戏都有相应的功能,根据这些功能的结果,将为每个人创建一个键值对。

我知道scores[name] = {game: 1}行是有问题的,因为它只会在上一场比赛中覆盖scores[name]字典。

我也尝试了下面的代码。

manager = Manager()
scores = manager.dict()

def add_scores(name, game):
    global scores
    if name not in scores:
        scores[name] = {}
    try:
        scores[name][game] += 1
    except Exception as e:
        print(e)

在这种情况下,print(e)给出了game的值。如果我改用scores[name][game] = 1进行测试,则没有错误,但是字典为空,例如{'John': {}, 'Alice': {}}。我似乎无法仅通过为键指定一个值来向字典添加新键。

如何添加到词典中?

2 个答案:

答案 0 :(得分:3)

关键是要记住, Manager.dict仅在 setitem 期间同步。如果直接编辑值对象,Manager.dict将看不到更改,因此不会同步。 (因为从Manager.dict的角度来看,键仍然指向相同的值对象; Manager.dict不会监视指向的值对象内部的更改。)

以下是在python 3.9和python 3.6中运行的版本(及其之间的每个python版本):

from multiprocessing import Process, Manager


def add_scores(_scores, name, game):
    # First get the inner dict
    # No need to use .setdefault() because we're going to
    # overwrite the value later, anyways
    nmgm = _scores.get(name, {})
    # Modify it
    nmgm[game] = nmgm.get(game, 0) + 1
    # Write it back so Manager.dict will sync
    _scores[name] = nmgm


players = {
    "Alex": ["Soccer", "Soccer", "Tennis"], 
    "Bob": ["Tennis", "Quidditch", "Soccer", "Tennis"]
    }


if __name__ == '__main__':
    manager = Manager()
    scores = manager.dict()

    for iplayer, games in players.items():
        for igame in games:
            p = Process(target=add_scores, args=(scores, iplayer, igame))
            p.start()
            p.join()

    print(scores)

请注意,我不使用global,而是将Manager.dict的实例传递给工作进程。在我的Python安装中,在manager结构外部初始化scores__main__产生了RuntimeError

结果:

{'Alex': {'Soccer': 2, 'Tennis': 1}, 'Bob': {'Tennis': 2, 'Quidditch': 1, 'Soccer': 1}}

答案 1 :(得分:1)

您的内部字典也需要manager.dict(),因为它们也需要共享。这应该工作

def add_scores(name, game):
    global scores
    if name not in scores:
        scores[name] = manager.dict()

    scores[name][game] = scores[name].get(game, 0) + 1

我还使用.get(game, 0)来获取game的值,默认值为零,以摆脱try-catch和if块。

请记住,一旦完成,您将需要解开内部嵌套的字典,因为它们将是DictProxy个对象。

import copy
d = copy.deepcopy(data)
for key, val in d.items():
    d[key] = copy.deepcopy(val)
print(d)

示例(与Mac上的Intel发行的Python 3.6.3配合使用):

from multiprocessing import Process, Manager
import copy

manager = Manager()
scores = manager.dict()

def add_scores(name, game):
    global scores
    if name not in scores:
        scores[name] = manager.dict()

    scores[name][game] = scores[name].get(game, 0) + 1

players = {
    "Alex": ["Soccer", "Soccer", "Tennis"], 
    "Bob": ["Tennis", "Quidditch", "Soccer", "Tennis"]
    }

for iplayer, games in players.items():
    for igame in games:
        p = Process(target=add_scores, args=(iplayer, igame))
        p.start()
        p.join()


d = copy.deepcopy(scores)
for key, val in d.items():
    d[key] = copy.deepcopy(val)

print(d)

给出输出:

{
  'Alex': {'Soccer': 2, 'Tennis': 1}, 
  'Bob': {'Tennis': 2, 'Quidditch': 1, 'Soccer': 1}
}