我正在使用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': {}}
。我似乎无法仅通过为键指定一个值来向字典添加新键。
如何添加到词典中?
答案 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}
}