Ответ 1
Самый простой способ, на мой взгляд, примерно такой:
new_dict = {**old_dict, 'changed_val': value, **other_new_vals_as_dict}
Очень часто мне нужно создавать dicts, которые отличаются друг от друга одним или двумя элементами. Вот что я обычно делаю:
setup1 = {'param1': val1,
'param2': val2,
'param3': val3,
'param4': val4,
'paramN': valN}
setup2 = copy.deepcopy(dict(setup1))
setup2.update({'param1': val10,
'param2': val20})
Тот факт, что есть точка в программе, в которой setup2
является идентичной копией setup1
, заставляет меня нервничать, поскольку я боюсь, что в какой-то момент жизни программы две линии могут быть разделены, который является скользким наклоном к слишком большому количеству ошибок.
В идеале я хотел бы иметь возможность выполнить это действие в одной строке кода (что-то вроде этого):
setup2 = dict(setup1).merge({'param1': val10,
'param2': val20})
Конечно, я могу использовать точку с запятой, чтобы сжать две команды в одну физическую линию, но это выглядит довольно уродливо для меня. Есть ли другие варианты?
Самый простой способ, на мой взгляд, примерно такой:
new_dict = {**old_dict, 'changed_val': value, **other_new_vals_as_dict}
setup2 = dict(setup1.items() + {'param1': val10, 'param2': val20}.items())
Таким образом, если новые ключи не существуют в setup1
, они добавляются, иначе они заменяют старые пары ключ/значение.
Создайте для этого функцию.
Ваше намерение будет более четким, если вы его используете в коде, и вы можете обрабатывать сложные решения (например, глубокие или мелкие копии) в одном месте.
def copy_dict(source_dict, diffs):
"""Returns a copy of source_dict, updated with the new key-value
pairs in diffs."""
result=dict(source_dict) # Shallow copy, see addendum below
result.update(diffs)
return result
И теперь копия является атомарной, если не использовать нити:
setup2=copy_dict(setup1, {'param1': val10, 'param2': val20})
Для примитивов (целых чисел и строк) нет необходимости в глубокой копии:
>>> d1={1:'s', 2:'g', 3:'c'}
>>> d2=dict(d1)
>>> d1[1]='a'
>>> d1
{1: 'a', 2: 'g', 3: 'c'}
>>> d2
{1: 's', 2: 'g', 3: 'c'}
Если вам нужна глубокая копия, используйте модуль copy
:
result=copy.deepcopy(source_dict) # Deep copy
вместо:
result=dict(setup1) # Shallow copy
Убедитесь, что все объекты в вашем словаре поддерживают глубокую копию (любой объект, который может быть pickled
должен делать).
setup2 = dict((k, {'param1': val10, 'param2': val20}.get(k, v))
for k, v in setup1.iteritems())
Это работает только в том случае, если все ключи словаря обновлений уже содержатся в setup1
.
Если все ваши клавиши являются строками, вы также можете сделать
setup2 = dict(setup1, param1=val10, param2=val20)
Вы можете использовать аргументы ключевого слова в конструкторе словаря для своих обновлений
new = dict(old, a=1, b=2, c=3)
# You can also unpack your modifications
new = dict(old, **mods)
Это эквивалентно:
new = old.copy()
new.update({"a": 1, "b": 2, "c": 3})
Примечание: dict.copy()
создает копию неглубокой.
Если вам просто нужно создать новый dict с элементами из более чем одного dict, вы можете использовать:
dict(a.items() + b.items())
Если оба "a" и "b" имеют один и тот же ключ, результат будет иметь значение из b. Если вы используете Python 3, конкатенация не будет работать, но вы можете сделать то же самое, запустив генераторы в списки или используя функцию itertools.chain.
Вы можете написать свой собственный класс с помощью обертки UserDict
и просто добавить dict
как
# setup1 is of Dict type (see below)
setup2 = setup1 + {'param1': val10}
Все, что вам нужно сделать, это
UserDict
в качестве базового класса__add__
для него.Что-то вроде:
class Dict(dict):
def __add__(self, _dict):
if isinstance(_dict, dict):
tmpdict = Dict(self)
tmpdict.update(_dict)
return tmpdict
else:
raise TypeError
def __radd__(self, _dict):
return Dict.__add__(self, _dict)
Это расширение для хорошего ответа, опубликованного Adam Matan:
def copy_dict(d, diffs={}, **kwargs):
res = dict(d)
res.update(diffs)
res.update(kwargs)
return res
Единственное различие заключается в добавлении kwargs. Теперь можно написать
setup2 = copy_dict(setup1, {'param1': val10, 'param2': val20})
или
setup2 = copy_dict(setup1, param1=val10, param2=val20)