Python "розширити" для словника


462

Який найкращий спосіб поширити словник на інший? Наприклад:

>>> 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

25
Я знав для списків [], то, я думаю, може бути робота для інших, не екстремально ;-)
FerranB

Відповіді:


694

6
Прочитавши документи, ви зрозумієте, чому існує "оновлення", але немає "розширення".
georg

58
майте на увазі, що update () безпосередньо змінює дікт і повертає None.
e18r

5
Але що робити, якщо ви хочете розширити дікт лише значеннями, які вже не визначені (тобто не перезаписуючи існуючі значення)? Наприклад, оновити дікт {"a":2, "b":3}на дікт {"b":4, "c":5}до диктату {"a":2, "b":3,"c":5}? Звичайно, це можливо за update()допомогою переміщення деяких речей, але було б приємніше, якби це можна було виконати лише одним рядком ...
Nearoo

17
@Nearoo - просто оновіть зворотний шлях; замість x.update (y) [який би перезаписав значення x з y], використовуйте y.update (x) [який перезаписує значення y на x] і використовуйте y як обраний вами дік для подальших операцій
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 є a string.


3
Документацію для пошуку dictлегко знайти, тоді **як трохи складніше (ключове слово - kwargs ). Ось приємне пояснення: saltycrane.com/blog/2008/01/…
johndodo

4
це може використовуватися для генерації другої змінної за допомогою однієї команди, тоді basket_one.update(<dict>)як, як було сказано в імені, оновлення існуючого словника (або клонованого).
furins

2
Зауважте, що в Python 3 назви аргументів, а отже, і ключі **anotherdict, повинні бути рядками.
Петро Вікторін

Дякую @johndodo - я інтегрував ваші пропозиції до публікації.
Том Лейс

1
Приємна функціональна альтернатива прийнятої відповіді. Такий підхід бажаний, якщо вам потрібно безпосередньо використовувати нещодавно поєднаний дикт. (також дивіться коментар @ e18r щодо прийнятої відповіді).
chinnychinchin

45

Ви спробували використовувати розуміння словника зі складанням словника:

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

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

Інший спосіб зробити це за допомогою dict (ітерабельний, ** kwarg)

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

У Python 3.9 ви можете додати два dict за допомогою об'єднання | оператор

# use the merging operator |
c = a | b
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

5
FYI: це
невірний

2
Цей синтаксис є досить новим (Python 3.5)
pianoJames

24
a.update(b)

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


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.


1

Ви також можете використовувати колекції python.Chainmap, яка була представлена ​​в python 3.3.

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

Це має декілька можливих переваг, залежно від вашого використання. Вони більш докладно пояснені тут , але я короткий огляд:

  • У ланцюговій карті використовуються лише представлення словників, тому дані фактично не копіюються. Це призводить до більш швидкого ланцюжка (але повільнішого пошуку)
  • Жодна клавіша насправді не перезаписується, тому при необхідності ви знаєте, чи дані надходять від a чи b.

Це головним чином робить його корисним для таких речей, як словники конфігурації.


0

У випадку, якщо він вам потрібен як клас , ви можете розширити його dict і використовувати метод оновлення :

Class a(dict):
  # some stuff
  self.update(b)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.