Update: В Python 3.9 реализовано PEP 584 -- Add Union Operators To dict :
n
>>> {0: 'a', 1: 'b'} | {False: 'A', 2: 'C'}n{0: 'A', 1: 'b', 2: 'C'}n
n
объединение словарей с помощью | (union) операции: более левые ключи (как у | операции для set) выигрывают и более правые (поздние) значения выигрывают (как dict_add_keep_last() ниже).
n
Есть также и по месту операция (изменяет словарь) и можно передавать не только словари:
n
>>> d = {0: 'a', 1: 'b'}n>>> d |= [(False, 'A'), (2, 'C')]n>>> dn{0: 'A', 1: 'b', 2: 'C'}n
n
n
Cтарый ответ:
n
Потому что не ясно какую операцию + должен реализовывать для словарей. И предпочтительные для каждого конкретного случая варианты легко реализовать.
n
Из ""The Zen of Python"" (import this) :
n
Explicit is better than implicit.nIn the face of ambiguity, refuse the temptation to guess.nThere should be one-- and preferably only one --obvious way to do it.n
n
BDFL (2009) :
n
nBecause there so many different ways to think about this, it's better not to guess and force the user to be explicit.
n
n
Guido (2019): Why operators are useful .
n
Например (псевдо-код):
n
result = {'a': 1, 'b': 2} + {'a': 3, 'c': 0}n
n
Возможны разные ответы:
n
n- n
сохранять только последние значения ( PEP-0584 поведение )
nresult = {'a': 3, 'b': 2, 'c': 0}n
nможно реализовать так:
ndef dict_add_keep_last(a, b): # aka merged() or updated()n d = a.copy()n d.update(b)n retu dn
nВ специальных случаях, когда ключи являются строками можно без функции обойтись (в Питоне 2 (CPython) также разрешены произвольные ключи), пример :
nresult = dict(a, **b) # результат тот жеn
n Guido не любит такую конструкцию .
nИли для произвольных словарей в Питоне 3.5 ( PEP 0448 -- Additional Unpacking Generalizations ):
nresult = {**a, **b}n
nсм. Adding dictionaries together, Python (следуй по ссылкам по цепочке, есть хорошие ответы у каждого вопроса).
n n- n
сохранять первые значения (возможно ближе к тому как | операция реализована у set()):
nresult = {**b, **a} # Python 3.5, or else swap a, b: dict_add_keep_last(b, a)n
n n- n
суммировать значения как collections.Counter (Multiset semantics):
n>>> from collections import Counte>>> Counter(a) + Counter(b)nCounter({'a': 4, 'b': 2})n
nКлючи с нулевыми (и отрицательными) значениями ('c') не сохраняются.
n n- n
как-то по-другому комбинировать, чтобы не терять информацию, например, sum_dict() или:
nresult = {'a': [1, 3], 'b': 2, 'c': 0}n
nUse-case: повторяющиеся ключи в json объекте
n n- n
завершаться с ошибкой в случае ключей-дубликатов, пример .
n n
n
Никакой из представленных вариантов не является более очевидным (точнее разные люди могут считать разные варианты более очевидными). Более того, каждый из этих вариантов имеет право на существование и они не всегда взаимозаменяемы. Различные варианты сложения словарей используются не очень часто, поэтому важно, чтобы в каждом случае явно было указано, какой тип операции используется и не нужно было гадать (ошибки менее вероятны).
n
Идея обсуждалась в списке рассылки (python-ideas) неоднократно:
n
n- ""Adding ""+"" and ""+="" operators to dict"" (2015)
n- ""adding dictionaries"" (2014)
n- ""dict '+' operator and slicing support for pop"" (2009)
n
n
Мелкие замечания (не имеют отношения к ""почему"", но полезны для темы ""сложить два словаря""):
n
n- n
тип возвращаемого значения для a + b выражения, как обычно, не очевиден и может зависеть от типа a и b например, выражение a += b, может ""поменять"" тип a:
n>>> from decimal import Decimaln>>> a = 1n>>> a += Decimal(2)n>>> anDecimal('3')n
n n- n
также, в случае нескольких словарей, + синтаксис поощряет неэффективный (память, время исполнения) код для больших словарей, например, a += b + c + d + .. (O(N*k**2)) можно записать б��лее эффективно как (O(N*k)):
nfor it in [b, c, d, ..]:n a.update(it)n
n n- n
иногда (например, для больших словарей, в которых только некоторые ключи являются интересными) можно ""лениво"" (O(k)) слить словари, используя ChainMap:
ntry: n from collections import ChainMapnexcept ImportError: # Python 2n from ConfigParser import _Chainmap as ChainMapn
n pylookup = ChainMap(locals(), globals(), vars(builtins))
n n
n
n
nЕсли вам не нравится +, можно же было сделать fluent interface - чтобы dict.update() возвращал self.
n
n
Потому что в Питоне методы, которые изменяют объект, обычно возвращают None, типичный пример: some_list.sort() vs. sorted(some_list). Питон следует принципу Command–query separation .
n