Python «расширить» для словаря

464

Какой лучший способ расширить словарь с другим? Например:

>>> a = { "a" : 1, "b" : 2 }
>>> b = { "c" : 3, "d" : 4 }
>>> a
{'a': 1, 'b': 2}
>>> b
{'c': 3, 'd': 4}

Я ищу любую операцию, чтобы получить этот избегающий forцикл:

{ "a" : 1, "b" : 2, "c" : 3, "d" : 4 }

Я хочу сделать что-то вроде:

a.extend(b)  # This does not work
FerranB
источник
25
Я знал, что для списков [], то я полагаю, что может быть работа для других, а не посторонний ;-)
FerranB

Ответы:

696
a.update(b)

Последняя документация стандартной библиотеки Python

Ник Фортескью
источник
6
Прочитав документы, вы поймете, почему существует «обновление», но нет «расширения».
Георг
58
Имейте в виду, что update () напрямую изменяет dict и возвращает None.
e18r
5
Но что, если вы хотите расширить диктат только значениями, которые еще не определены (то есть не перезаписывать существующие значения)? Например, обновить dict {"a":2, "b":3}с помощью dict {"b":4, "c":5}to dict {"a":2, "b":3,"c":5}? Конечно, это можно использовать update(), перемещая некоторые вещи, но было бы лучше, если бы это можно было сделать только в одной строке ...
Nearoo
17
@Nearoo - просто обнови обратным способом; вместо x.update (y) [который будет перезаписывать значения x с помощью y], используйте y.update (x) [который перезаписывает значения y с помощью x] и используйте y в качестве выбранного для дальнейших операций dict
jonathanl
Имейте ввиду, что updateмолча перезаписывает существующие записи. То есть любые значения в bперезаписывают значения aдля перекрывающихся ключей.
CGFoX
186

Красивая жемчужина в этом закрытом вопросе :

«Единый путь», не изменяющий ни один из входных диктов,

basket = dict(basket_one, **basket_two)

Узнайте, что **basket_two(здесь **) означает здесь .

В случае конфликта элементы из basket_twoбудут отменять те из basket_one. Что касается однострочников, то это довольно читабельно и прозрачно, и у меня нет никаких сложностей против того, чтобы использовать его в любое время, когда пригодится изречение, представляющее собой смесь двух других (любой читатель, который испытывает затруднения в понимании этого, на самом деле будет очень хорошо способ, которым это побуждает его или ее к изучению dictи **форме ;-). Так, например, используется как:

x = mungesomedict(dict(adict, **anotherdict))

достаточно частые случаи в моем коде.

Первоначально представленный Алекс Мартелли

Примечание: в Python 3 это будет работать, только если каждый ключ в basket_two - это string.

Том Лейс
источник
3
Документацию для dictлегко найти, хотя **это немного сложнее (ключевое слово kwargs ). Вот хорошее объяснение: saltycrane.com/blog/2008/01/…
johndodo
4
это может использоваться для генерации второй переменной с помощью одной команды, тогда basket_one.update(<dict>)как , как следует из названия, обновляет существующий словарь (или клонированный).
Фуринс
2
Обратите внимание, что в Python 3 имена аргументов и, следовательно, ключи **anotherdictдолжны быть строками.
Петр Викторин
Спасибо @johndodo - я включил ваши предложения в пост.
Том Лейс
1
Хорошая функциональная альтернатива принятому ответу. Такой подход желателен, если вам нужно напрямую использовать вновь объединенный дикт. (также см. комментарий @ e18r о принятом ответе).
Чиннычинчин
45

Вы пробовали использовать словарное понимание со словарным отображением:

a = {'a': 1, 'b': 2}
b = {'c': 3, 'd': 4}

c = {**a, **b}
# c = {"a": 1, "b": 2, "c": 3, "d": 4}

Другой способ сделать это - использовать dict (iterable, ** kwarg)

c = dict(a, **b)
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

В Python 3.9 вы можете добавить два dict, используя union | оператор

# use the merging operator |
c = a | b
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
Влад Безден
источник
5
К вашему сведению: это
неверный
2
Этот синтаксис довольно новый (Python 3.5)
pianoJames
24
a.update(b)

Добавит ключи и значения от b к a , перезаписывая, если уже есть значение для ключа.

Vartec
источник
17

Как уже упоминали другие, a.update(b)для некоторых диктов aи bбудет достигнут результат, который вы просили в своем вопросе. Тем не менее, я хочу отметить, что я много раз видел extendспособ отображения / набор объектов , которые желают в синтаксисе a.extend(b), a«s значения не должны быть перезаписаны b» значениями s. a.update(b)перезаписывает aзначения, и поэтому не является хорошим выбором для extend.

Обратите внимание, что некоторые языки вызывают этот метод defaultsили inject, как его можно представить, как способ ввода значений b (которые могут быть набором значений по умолчанию) в словарь без перезаписи значений, которые могут уже существовать.

Конечно, вы можете просто заметить, что a.extend(b)это почти так же, как b.update(a); a=b. Чтобы удалить назначение, вы можете сделать это так:

def extend(a,b):
    """Create a new dictionary with a's properties extended by b,
    without overwriting.

    >>> extend({'a':1,'b':2},{'b':3,'c':4})
    {'a': 1, 'c': 4, 'b': 2}
    """
    return dict(b,**a)

Спасибо Тому Лису за эту умную идею, использующую конструктор без побочных эффектов dictдля extend.

eblume
источник
1

Вы также можете использовать коллекции python.Chainmap, который был представлен в python 3.3.

from collections import Chainmap
c = Chainmap(a, b)
c['a'] # returns 1

Это имеет несколько возможных преимуществ, в зависимости от вашего варианта использования. Они объяснены более подробно здесь , но я дам краткий обзор:

  • Цепная карта использует только представления словарей, поэтому данные фактически не копируются. Это приводит к более быстрой цепочке (но медленнее поиск)
  • На самом деле никакие ключи не перезаписываются, поэтому при необходимости вы знаете, поступают ли данные с a или b.

Это в основном делает его полезным для таких вещей, как словари конфигурации.

Ivo Merchiers
источник
0

Если вам это нужно как классу , вы можете расширить его с помощью dict и использовать update метод :

Class a(dict):
  # some stuff
  self.update(b)
Желько Шевич
источник