Подтвердить что ты не робот

Как скопировать 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})

Конечно, я могу использовать точку с запятой, чтобы сжать две команды в одну физическую линию, но это выглядит довольно уродливо для меня. Есть ли другие варианты?

4b9b3361

Ответ 1

Самый простой способ, на мой взгляд, примерно такой:

new_dict = {**old_dict, 'changed_val': value, **other_new_vals_as_dict}

Ответ 2

setup2 = dict(setup1.items() + {'param1': val10, 'param2': val20}.items())

Таким образом, если новые ключи не существуют в setup1, они добавляются, иначе они заменяют старые пары ключ/значение.

Ответ 3

Решение

Создайте для этого функцию.

Ваше намерение будет более четким, если вы его используете в коде, и вы можете обрабатывать сложные решения (например, глубокие или мелкие копии) в одном месте.

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 должен делать).

Ответ 4

setup2 = dict((k, {'param1': val10, 'param2': val20}.get(k, v))
              for k, v in setup1.iteritems())

Это работает только в том случае, если все ключи словаря обновлений уже содержатся в setup1.

Если все ваши клавиши являются строками, вы также можете сделать

setup2 = dict(setup1, param1=val10, param2=val20)

Ответ 5

Вы можете использовать аргументы ключевого слова в конструкторе словаря для своих обновлений

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() создает копию неглубокой.

Ответ 6

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

dict(a.items() + b.items())

Если оба "a" и "b" имеют один и тот же ключ, результат будет иметь значение из b. Если вы используете Python 3, конкатенация не будет работать, но вы можете сделать то же самое, запустив генераторы в списки или используя функцию itertools.chain.

Ответ 7

Вы можете написать свой собственный класс с помощью обертки 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)

Ответ 8

Это расширение для хорошего ответа, опубликованного 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)