Почему нельзя просто взять и сложить два словаря?
📁 кортеж, python, пример
Почему списки, кортежи, множества можно, а словари - нельзя?
Если вам не нравится +, можно же было сделать fluent interface - чтобы dict.update() возвращал self.
Самое лучшее, что я нашел - dict(dict1, key1=value1).
Пример использования:
base_config = {'key1': 'val1'}func1(base_config + {'key2': 'val2'})func2(base_config + {'key3': 'val3'})
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'}nnобъединение словарей с помощью | (union) операции: более левые ключи (как у | операции для set) выигрывают и более правые (поздние) значения выигрывают (как dict_add_keep_last() ниже).
Есть также и по месту операция (изменяет словарь) и можно передавать не только словари:
n>>> d = {0: 'a', 1: 'b'}n>>> d |= [(False, 'A'), (2, 'C')]n>>> dn{0: 'A', 1: 'b', 2: 'C'}nnn
Cтарый ответ:
nПотому что не ясно какую операцию + должен реализовывать для словарей. И предпочтительные для каждого конкретного случая варианты легко реализовать.
Из ""The Zen of Python"" (import this) :
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.nnBDFL (2009) :
nnnBecause there so many different ways to think about this, it's better not to guess and force the user to be explicit.
n
Guido (2019): Why operators are useful .
nНапример (псевдо-код):
nresult = {'a': 1, 'b': 2} + {'a': 3, 'c': 0}nnВозможны разные ответы:
n- n
- n
сохранять только последние значения ( PEP-0584 поведение )
n
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В специальных случаях, когда ключи являются строками можно без функции обойтись (в Питоне 2 (CPython) также разрешены произвольные ключи), пример :
n
nresult = dict(a, **b) # результат тот жеnGuido не любит такую конструкцию .
nИли для произвольных словарей в Питоне 3.5 ( PEP 0448 -- Additional Unpacking Generalizations ):
n
nresult = {**a, **b}nсм. Adding dictionaries together, Python (следуй по ссылкам по цепочке, есть хорошие ответы у каждого вопроса).
n n - n
сохранять первые значения (возможно ближе к тому как
n|операция реализована уset()):
nresult = {**b, **a} # Python 3.5, or else swap a, b: dict_add_keep_last(b, a)nn - n
суммировать значения как
ncollections.Counter(Multiset semantics):
n>>> from collections import Counte>>> Counter(a) + Counter(b)nCounter({'a': 4, 'b': 2})nКлючи с нулевыми (и отрицательными) значениями (
n'c') не сохраняются. n - n
как-то по-другому комбинировать, чтобы не терять информацию, например, sum_dict() или:
n
nresult = {'a': [1, 3], 'b': 2, 'c': 0}nUse-case: повторяющиеся ключи в json объекте
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
тип возвращаемого значения для
na + bвыражения, как обычно, не очевиден и может зависеть от типаaиbнапример, выражениеa += b, может ""поменять"" типa:
n>>> from decimal import Decimaln>>> a = 1n>>> a += Decimal(2)n>>> anDecimal('3')nn - n
также, в случае нескольких словарей,
n+синтаксис поощряет неэффективный (память, время исполнения) код для больших словарей, например,a += b + c + d + ..(O(N*k**2)) можно записать б��лее эффективно как (O(N*k)):
nfor it in [b, c, d, ..]:n a.update(it)nn - n
иногда (например, для больших словарей, в которых только некоторые ключи являются интересными) можно ""лениво"" (
nO(k)) слить словари, используяChainMap:
ntry: n from collections import ChainMapnexcept ImportError: # Python 2n from ConfigParser import _Chainmap as ChainMapn
npylookup = ChainMap(locals(), globals(), vars(builtins))n
n
nnЕсли вам не нравится +, можно же было сделать fluent interface - чтобы dict.update() возвращал self.
n
Потому что в Питоне методы, которые изменяют объект, обычно возвращают None, типичный пример: some_list.sort() vs. sorted(some_list). Питон следует принципу Command–query separation .
Войдите чтобы оставить ответ