Словарь дает значения для определенного ключа, но другие получают те же значения - PullRequest
1 голос
/ 18 января 2020

Я хочу создать словарь для записи точности при запуске программы. Есть некоторая проблема, когда я даю значения определенному ключу

Здесь я создаю словарь для записи точности, когда он поезда или проверки

acc = dict.fromkeys(['train', 'val'], dict.fromkeys(['pa', 'iou', 'dice'], 0))

Оригинальный словарь выглядит следующим образом

{'train': {'pa': 0, 'iou': 0, 'dice': 0}, 'val': {'pa': 0, 'iou': 0, 'dice': 0}}

Теперь я даю некоторые значения для тестирования

acc['train']['pa'] = 0.9
acc['train']['iou'] = 0.8
acc['train']['dice'] = 0.7

Проблемы все значения в ключе val становятся одинаковыми

{'train': {'pa': 0.9, 'iou': 0.8, 'dice': 0.7}, 'val': {'pa': 0.9, 'iou': 0.8, 'dice': 0.7}}

Ответы [ 2 ]

1 голос
/ 18 января 2020

Это потому, что dict.fromkeys(['pa', 'iou', 'dice'], 0) вызывается ровно один раз, а не один раз для каждого ключа в acc.

>>> acc['train'] is acc['val']                                                  
True

Словари - это один и тот же объект в памяти, у вас есть только два способа получить к нему доступ - через acc['train'] и acc['val'].

Вы можете использовать defaultdict с функцией, которая создает новый словарь по требованию:

>>> from collections import defaultdict                                         
>>> d = defaultdict(lambda: {'pa': 0, 'iou': 0, 'dice': 0})                     
>>> d['train']                                                                  
{'pa': 0, 'iou': 0, 'dice': 0}
>>> d['val']                                                                    
{'pa': 0, 'iou': 0, 'dice': 0}
>>> d['train']['pa'] = 1                                                        
>>> d['train']                                                                  
{'pa': 1, 'iou': 0, 'dice': 0}
>>> d['val']                                                                    
{'pa': 0, 'iou': 0, 'dice': 0}

Однако имейте в виду, что это создает Новый словарь каждый раз, когда вы получаете доступ к новому ключу:

>>> d['foo']                                                                    
{'pa': 0, 'iou': 0, 'dice': 0}

Если вы не хотите этого, создайте словарь для каждого ключа вручную с пониманием dict:

>>> keys = ['train', 'val']                                                     
>>> d = {k:{'pa': 0, 'iou': 0, 'dice': 0} for k in keys}
>>> d['train']['pa'] = 1                                                        
>>> d['train']                                                                  
{'pa': 1, 'iou': 0, 'dice': 0}
>>> d['val']                                                                    
{'pa': 0, 'iou': 0, 'dice': 0}
1 голос
/ 18 января 2020

Если предоставленное значение является изменяемым объектом (чье значение может быть изменено), таким как список, словарь и т. Д. c., Когда изменяемый объект изменяется, каждый элемент последовательности также обновляется. Это связано с тем, что каждому элементу назначается ссылка на один и тот же объект (указывает на один и тот же объект в памяти).

В вашей задаче dict.fromkeys(['pa', 'iou', 'dice'], 0) возвращает словарь с изменяемым типом, поэтому каждый элемент присваивается одному и тому же объекту.

Чтобы избежать этой проблемы, вы можете использовать словарное понимание.

from copy import copy
# keys
keys = ['train', 'val']
value = dict.fromkeys(['pa', 'iou', 'dice'], 0 )

acc = { key : copy(value) for key in keys }

print(acc)

# updating the value
acc['train']['pa'] = 2 
print(acc)

Источник: https://www.programiz.com/python-programming/methods/dictionary/fromkeys

...