python transformar Como mesclar dois dicionários em uma única expressão?




transformar objeto em dicionario python (24)

No Python 3, você pode usar collections.ChainMap que agrupa vários dicts ou outros mapeamentos para criar uma única visualização atualizável:

from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))

Eu tenho dois dicionários Python, e eu quero escrever uma única expressão que retorna esses dois dicionários, mesclados. O método update() seria o que eu preciso, se ele retornasse seu resultado em vez de modificar um dict in-place.

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}

Como posso obter esse dit final mesclado em z , não em x ?

(Para ser mais claro, o último dict.update() de conflito do dict.update() é o que eu estou procurando também.)


(Apenas para Python2.7 *; existem soluções mais simples para o Python3 *.)

Se você não é avesso a importar um módulo de biblioteca padrão, você pode fazer

 from functools import reduce def merge_dicts(*dicts): return reduce(lambda a, d: a.update(d) or a, dicts, {}) 

(O or abit no lambdaé necessário porque dict.updatesempre retorna Noneno sucesso.)


z={i:d[i] for d in [x,y] for i in d}

>>> print z
{'a': 1, 'c': 11, 'b': 10}

Entre essas respostas duvidosas e duvidosas, esse exemplo brilhante é a única maneira boa de fundir ditos em Python, endossado pelo ditador vitalício Guido van Rossum ! Alguém sugeriu metade disso, mas não o colocou em uma função.

dict(x.items() | y.items())

dá:

dict(x.viewitems() | y.viewitems())

Com base em idéias aqui e em outros lugares, eu compreendi uma função:

0.049465 sec for: dict(x, **y)
0.033729 sec for: x.update(y)                   
0.150380 sec for: dict(x.items() + y.items())   
0.083120 sec for: for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]

confirm b elements are added: {'a': 1, 'c': 11, 'b': 12}

Uso (testado em python 3):

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> { key: y[key] if key in y else x[key]
      for key in set(x) + set(y)
    }

Você poderia usar um lambda em vez disso.



Embora a pergunta já tenha sido respondida várias vezes, essa solução simples para o problema ainda não foi listada.

x = {'a':1, 'b':2}
y = {'b':10, 'c':11}
z = (lambda a, b: (lambda a_copy: a_copy.update(b) or a_copy)(a.copy()))(x, y)
print z
{'a': 1, 'c': 11, 'b': 10}
print x
{'a': 1, 'b': 2}

É tão rápido quanto z0 e o mal z2 mencionado acima, mas é fácil de entender e mudar.


Para o Python 2:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x, z = dict(x), x.update(y) or x
>>> x
{'a': 1, 'b': 2}
>>> y
{'c': 11, 'b': 10}
>>> z
{'a': 1, 'c': 11, 'b': 10}

Para o Python 3:

import timeit

n=100000
su = """
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
"""

def timeMerge(f,su,niter):
    print "{:4f} sec for: {:30s}".format(timeit.Timer(f,setup=su).timeit(n),f)

timeMerge("dict(x, **y)",su,n)
timeMerge("x.update(y)",su,n)
timeMerge("dict(x.items() + y.items())",su,n)
timeMerge("for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] ",su,n)

#confirm for loop adds b entries together
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]
print "confirm b elements are added:",x

Dá saída: {'a': 1, 'c': 11, 'b': 10}


 from collections import Counter dict1 = {'a':1, 'b': 2} dict2 = {'b':10, 'c': 11} result = dict(Counter(dict1) + Counter(dict2)) 

Isso deve resolver seu problema.


No Python 3.5, você pode descompactar **para criar um novo dicionário. Este método não foi mostrado em respostas anteriores. Além disso, é melhor usar em {}vez de dict(). Porque {}é um literal python e dict()envolve uma chamada de função.

 dict1 = {'a':1} dict2 = {'b':2} new_dict = {**dict1, **dict2} >>>new_dict {'a':1, 'a':2} 

Embora as respostas sejam boas para esse dicionário superficial , nenhum dos métodos definidos aqui faz uma mesclagem de dicionário profunda.

Exemplos a seguir:

{'two': True, 'one': {'extra': False}}

Seria de esperar um resultado de algo como isto:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items()+y.items())
print(z)

Em vez disso, temos isso:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items()|y.items())
print(z)

A entrada 'one' deveria ter 'depth_2' e 'extra' como itens dentro de seu dicionário se realmente fosse uma mesclagem.

Usando cadeia também, não funciona:

def merge(*dicts, **kv): 
      return { k:v for d in list(dicts) + [kv] for k,v in d.items() }

Resulta em:

assert (merge({1:11,'a':'aaa'},{1:99, 'b':'bbb'},foo='bar')==\
    {1: 99, 'foo': 'bar', 'b': 'bbb', 'a': 'aaa'})

assert (merge(foo='bar')=={'foo': 'bar'})

assert (merge({1:11},{1:99},foo='bar',baz='quux')==\
    {1: 99, 'foo': 'bar', 'baz':'quux'})

assert (merge({1:11},{1:99})=={1: 99})

A mesclagem profunda que o rcwesick deu também cria o mesmo resultado.

Sim, funcionará para mesclar os dicionários de exemplo, mas nenhum deles é um mecanismo genérico para mesclar. Eu atualizarei isso mais tarde assim que eu escrever um método que faça uma mesclagem verdadeira.


O Python 3.5 (PEP 448) permite uma opção mais agradável de sintaxe:

def dict_merge(a, b):
  c = a.copy()
  c.update(b)
  return c

new = dict_merge(old, extras)

Ou mesmo

print dict_merge(
      {'color':'red', 'model':'Mini'},
      {'model':'Ferrari', 'owner':'Carl'})

Em uma resposta de acompanhamento, você perguntou sobre o desempenho relativo dessas duas alternativas:

% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop

Na minha máquina, pelo menos (um x86_64 bastante comum rodando o Python 2.5.2), a alternativa z2 não é apenas mais curta e simples, mas também significativamente mais rápida. Você pode verificar isso por si mesmo usando o módulo timeit que vem com o Python.

Exemplo 1: dicionários idênticos mapeando 20 inteiros consecutivos para si mesmos:

z0 = dict(x)
z0.update(y)

z2 ganha por um fator de 3,5 ou mais. Diferentes dicionários parecem produzir resultados bastante diferentes, mas o z2 sempre parece estar à frente. (Se você obtiver resultados inconsistentes para o mesmo teste, tente transmitir -r com um número maior que o padrão 3.)

Exemplo 2: mapeamento de dicionários não sobrepostos 252 strings curtas para números inteiros e vice-versa:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop

z2 ganha por um fator de 10. Isso é uma grande vitória no meu livro!

Depois de comparar os dois, imaginei se o desempenho ruim do z1 poderia ser atribuído à sobrecarga de construção das duas listas de itens, o que, por sua vez, levou-me a pensar se essa variação poderia funcionar melhor:

z0 = x.copy()
z0.update(y)

Alguns testes rápidos, por exemplo

def merge(d1, d2, merge_fn=lambda x,y:y):
    """
    Merges two dictionaries, non-destructively, combining 
    values on duplicate keys as defined by the optional merge
    function.  The default behavior replaces the values in d1
    with corresponding values in d2.  (There is no other generally
    applicable merge strategy, but often you'll have homogeneous 
    types in your dicts, so specifying a merge technique can be 
    valuable.)

    Examples:

    >>> d1
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1)
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1, lambda x,y: x+y)
    {'a': 2, 'c': 6, 'b': 4}

    """
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge_fn(result[k], v)
        else:
            result[k] = v
    return result

leva-me a concluir que o z3 é um pouco mais rápido que o z1 , mas não tão rápido quanto o z2 . Definitivamente não vale a pena toda a digitação extra.

Esta discussão ainda está faltando algo importante, que é uma comparação de desempenho dessas alternativas com a maneira "óbvia" de mesclar duas listas: usando o método de update . Para tentar manter as coisas em pé de igualdade com as expressões, nenhuma das quais modifique x ou y, vou fazer uma cópia de x em vez de modificá-lo no local, como segue:

>>> from collections import ChainMap
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = ChainMap({}, y, x)
>>> for k, v in z.items():
        print(k, '-->', v)

a --> 1
b --> 10
c --> 11

Um resultado típico:

def deepupdate(original, update):
    """
    Recursively update a dict.
    Subdict's won't be overwritten but also updated.
    """
    for key, value in original.iteritems(): 
        if key not in update:
            update[key] = value
        elif isinstance(value, dict):
            deepupdate(value, update[key]) 
    return update

Em outras palavras, z0 e z2 parecem ter desempenho essencialmente idêntico. Você acha que isso pode ser uma coincidência? Eu não....

Na verdade, eu iria ao ponto de afirmar que é impossível que o código Python puro seja melhor do que isso. E se você puder fazer algo significativamente melhor em um módulo de extensão C, imagino que o pessoal do Python possa estar interessado em incorporar seu código (ou uma variação em sua abordagem) no núcleo do Python. Python usa dict em muitos lugares; otimizar suas operações é um grande negócio.

Você também pode escrever isso como

pluto_original = {
    'name': 'Pluto',
    'details': {
        'tail': True,
        'color': 'orange'
    }
}

pluto_update = {
    'name': 'Pluutoo',
    'details': {
        'color': 'blue'
    }
}

print deepupdate(pluto_original, pluto_update)

como Tony faz, mas (não surpreendentemente) a diferença na notação acaba por não ter qualquer efeito mensurável no desempenho. Use o que parece certo para você. Claro, ele está absolutamente correto em apontar que a versão de duas declarações é muito mais fácil de entender.


Solução simples usando itertools que preserva a ordem (os últimos dicts têm precedência)

import collections
a = {1: 1, 2: 2}
b = {2: 3, 3: 4}
c = {3: 5}

r = dict(collections.ChainMap(a, b, c))
print(r)

E é uso:

{1: 1, 2: 2, 3: 4}

Se você acha que os lambdas são maus, então não leia mais. Conforme solicitado, você pode escrever a solução rápida e com eficiência de memória com uma expressão:

In [1]: from collections import ChainMap
In [2]: from string import ascii_uppercase as up, ascii_lowercase as lo; x = dict(zip(lo, up)); y = dict(zip(up, lo))
In [3]: chainmap_dict = ChainMap(y, x)
In [4]: union_dict = dict(x.items() | y.items())
In [5]: timeit for k in union_dict: union_dict[k]
100000 loops, best of 3: 2.15 µs per loop
In [6]: timeit for k in chainmap_dict: chainmap_dict[k]
10000 loops, best of 3: 27.1 µs per loop

Como sugerido acima, usar duas linhas ou escrever uma função é provavelmente o melhor caminho a percorrer.


Abuso levando a uma solução de uma expressão para a resposta de Mateus :

def union2(dict1, dict2):
    return dict(list(dict1.items()) + list(dict2.items()))

Você disse que queria uma expressão, então eu abusei de lambda para vincular um nome e tuplas para substituir o limite de uma expressão de lambda. Sinta-se livre para se encolher.

Você também pode fazer isso, claro, se não se importar em copiá-lo:

def union(*dicts):
    return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))

from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))

O problema que tenho com as soluções listadas até agora é que, no dicionário mesclado, o valor da chave "b" é 10, mas, na minha opinião, deveria ser 12. À essa luz, apresento o seguinte:

from functools import reduce

def merge_dicts(*dicts):
    return reduce(lambda a, d: a.update(d) or a, dicts, {})

Resultados:

dict1 = {'a':1}
dict2 = {'b':2}
new_dict = {**dict1, **dict2}
>>>new_dict
{'a':1, 'a':2}

Como posso mesclar dois dicionários Python em uma única expressão?

Para os dicionários x e y , z torna-se um dicionário mesclado superficialmente com valores de y substituindo os de x .

  • No Python 3.5 ou superior:

    z = {**x, **y}
    w = {'foo': 'bar', 'baz': 'qux', **y}  # merge a dict with literal values
    
  • No Python 2, (ou 3.4 ou inferior) escreva uma função:

    def merge_two_dicts(x, y):
        z = x.copy()   # start with x's keys and values
        z.update(y)    # modifies z with y's keys and values & returns None
        return z
    

    e agora:

    z = merge_two_dicts(x, y)
    

Explicação

Digamos que você tenha dois dicts e queira mesclá-los em um novo dict sem alterar os ditos originais:

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

O resultado desejado é obter um novo dicionário ( z ) com os valores mesclados e os valores do segundo ditado substituindo os valores do primeiro.

>>> z
{'a': 1, 'b': 3, 'c': 4}

Uma nova sintaxe para isso, proposta no PEP 448 e disponível a partir do Python 3.5 , é

z = {**x, **y}

E é de fato uma única expressão.

Note que podemos mesclar com notação literal também:

z = x.copy()
z.update(y) # which returns None since it mutates z

e agora:

def merge_two_dicts(x, y):
    """Given two dicts, merge them into a new dict as a shallow copy."""
    z = x.copy()
    z.update(y)
    return z

Agora está sendo mostrado como implementado no cronograma de lançamento do 3.5, PEP 478 , e agora chegou ao documento O Quede Novo no Python 3.5 .

No entanto, como muitas organizações ainda estão no Python 2, você pode querer fazer isso de uma maneira compatível com versões anteriores. A maneira classicamente pitônica, disponível no Python 2 e no Python 3.0-3.4, é fazer isso como um processo de duas etapas:

z = merge_two_dicts(x, y)

Em ambas as abordagens, y virá em segundo lugar e seus valores substituirão os valores de x , portanto, 'b' apontará para 3 em nosso resultado final.

Ainda não no Python 3.5, mas quero uma única expressão

Se você ainda não está no Python 3.5, ou precisa escrever código compatível com versões anteriores, e você quer isso em uma única expressão , a abordagem mais eficiente enquanto correta é colocá-lo em uma função:

def merge_dicts(*dict_args):
    """
    Given any number of dicts, shallow copy and merge into a new dict,
    precedence goes to key value pairs in latter dicts.
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result

e então você tem uma única expressão:

z = merge_dicts(a, b, c, d, e, f, g) 

Você também pode criar uma função para mesclar um número indefinido de ditos, de zero a um número muito grande:

z = dict(x.items() + y.items())

Essa função funcionará no Python 2 e 3 para todos os dicts. por exemplo, ditos a a g :

>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'

e os pares de valores de chave em g terão precedência sobre os ditos a a f , e assim por diante.

Críticas de Outras Respostas

Não use o que você vê na resposta anteriormente aceita:

>>> c = dict(a.items() | b.items())

No Python 2, você cria duas listas na memória para cada dit, cria uma terceira lista na memória com comprimento igual ao comprimento das duas primeiras juntas e depois descarta todas as três listas para criar o dit. No Python 3, isso falhará porque você está adicionando dois objetos dict_items juntos, não duas listas -

>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

e você teria que criá-los explicitamente como listas, por exemplo, z = dict(list(x.items()) + list(y.items())) . Isso é um desperdício de recursos e poder de computação.

Da mesma forma, a união de items() no Python 3 ( viewitems() no Python 2.7) também falhará quando os valores forem objetos que não podem ser vistos (como listas, por exemplo). Mesmo que seus valores sejam hasháveis, uma vez que os conjuntos são semanticamente desordenados, o comportamento é indefinido em relação à precedência. Então não faça isso:

>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}

Este exemplo demonstra o que acontece quando os valores são inalcançáveis:

z = dict(x, **y)

Aqui está um exemplo em que y deve ter precedência, mas o valor de x é retido devido à ordem arbitrária de conjuntos:

>>> c = dict(a, **b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

Outro hack que você não deve usar:

dict(a=1, b=10, c=11)

Isso usa o construtor dict , e é muito rápido e eficiente de memória (mesmo um pouco mais do que o nosso processo de duas etapas), mas a menos que você saiba exatamente o que está acontecendo aqui (ou seja, o segundo dict está sendo passado como construtor dit), é difícil de ler, não é o uso pretendido, e por isso não é Pythonic.

Aqui está um exemplo do uso sendo corrigido no django .

Os dicts são destinados a usar chaves hashable (por exemplo, frozensets ou tuplas), mas esse método falha no Python 3 quando as chaves não são strings.

{'a': 1, 'b': 10, 'c': 11}

Da lista de discussão , Guido van Rossum, o criador da linguagem, escreveu:

Eu estou bem em declarar o dict ({}, ** {1: 3}) ilegal, já que afinal é abuso do mecanismo **.

e

Aparentemente dict (x, ** y) está circulando como "cool hack" para "call x.update (y) e return x". Pessoalmente acho mais desprezível do que legal.

É meu entendimento (assim como o entendimento do criador da linguagem ) que o uso pretendido para o dict(**y) é para criar dicionários para fins de legibilidade, por exemplo:

>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}

ao invés de

{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7

Resposta aos comentários

Apesar do que Guido diz, dict(x, **y) está alinhado com a especificação do dict, que entre. funciona tanto para o Python 2 como para o 3. O fato de isso funcionar apenas para chaves de string é uma conseqüência direta de como os parâmetros de palavra-chave funcionam e não de um short-comming do dict. Nem está usando o operador ** neste lugar um abuso do mecanismo, na verdade ** foi projetado precisamente para passar ditos como palavras-chave.

Novamente, não funciona para 3 quando as teclas não são strings. O contrato de chamada implícito é que os espaços de nomes tomam ditads ordinários, enquanto os usuários devem apenas passar argumentos de palavra-chave que sejam strings. Todos os outros callables reforçaram isso. dict quebrou essa consistência no Python 2:

dict((k, v) for d in dicts for k, v in d.items())

Essa inconsistência foi ruim, dadas outras implementações do Python (Pypy, Jython, IronPython). Assim, foi corrigido no Python 3, já que esse uso poderia ser uma mudança urgente.

Eu submeto a você que é uma incompetência maliciosa escrever intencionalmente código que só funciona em uma versão de uma linguagem ou que só funciona dadas certas restrições arbitrárias.

Mais comentários:

dict(x.items() + y.items()) ainda é a solução mais legível para o Python 2. Readability counts.

Minha resposta: merge_two_dicts(x, y) na verdade, parece muito mais claro para mim, se estamos realmente preocupados com a legibilidade. E não é compatível com versões anteriores, já que o Python 2 é cada vez mais obsoleto.

{**x, **y} não parece lidar com dicionários aninhados. o conteúdo das chaves aninhadas é simplesmente sobrescrito, não mesclado [...] acabei sendo queimado por essas respostas que não se fundem recursivamente e fiquei surpreso que ninguém o mencionou. Na minha interpretação da palavra "mesclar", essas respostas descrevem "atualizar um comando com o outro" e não mesclar.

Sim. Devo encaminhá-lo de volta à pergunta, que está pedindo uma mescla superficial de dois dicionários, com os valores do primeiro sendo sobrescritos pelos segundos - em uma única expressão.

Assumindo dois dicionários de dicionários, pode-se mesclá-los recursivamente em uma única função, mas você deve ter cuidado para não modificar os ditames de nenhuma fonte, e o caminho mais seguro para evitar isso é fazer uma cópia ao atribuir valores. Como as chaves devem ser hash e geralmente são imutáveis, é inútil copiá-las:

import itertools
z = dict(itertools.chain(x.iteritems(), y.iteritems()))

Uso:

import timeit

Chegar com contingências para outros tipos de valor está muito além do escopo desta questão, então eu vou apontar a minha resposta à pergunta canônica sobre um "Dicionários de dicionários fundidos" .

Menos ad-hocs com desempenho mas correto

Essas abordagens são menos eficientes, mas fornecem um comportamento correto. Eles terão muito menos desempenho do que copy e update ou a nova descompactação, porque fazem a iteração em cada par de valores-chave em um nível mais alto de abstração, mas respeitam a ordem de precedência (os últimos dicts têm precedência)

Você também pode encadear os ditos manualmente dentro de uma compreensão dit:

>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.5726828575134277
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.163769006729126
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.iteritems(), y.iteritems()))))
1.1614501476287842
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
2.2345519065856934

ou no python 2.6 (e talvez em 2.4 quando as expressões geradoras foram introduzidas):

>>> min(timeit.repeat(lambda: {**x, **y}))
0.4094954460160807
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.7881555100320838
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.4525277839857154
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.items(), y.items()))))
2.3143140770262107
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
3.2069112799945287

itertools.chain encadeará os iteradores sobre os pares de valores-chave na ordem correta:

z = dict(x.items() + y.items())

Análise de desempenho

Eu só vou fazer a análise de desempenho dos usos conhecidos por se comportarem corretamente.

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}

O seguinte é feito no Ubuntu 14.04

No Python 2.7 (sistema Python):

>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}

No Python 3.5 (PPA deadsnakes):

z = x.copy()
z.update(y)

Recursos sobre dicionários


Isso pode ser feito com uma única compreensão de dit:

 >>> x = {'a':1, 'b': 2} >>> y = {'b':10, 'c': 11} >>> { key: y[key] if key in y else x[key] for key in set(x) + set(y) } 

Na minha opinião, a melhor resposta para a parte de "expressão única", como nenhuma função extra é necessária, e é curta.


Recursivamente / atualizar profundamente um dict

x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y} 
final
# {'a': 2, 'b': 1, 'c': 2}

Demonstração:

final = {'a': 1, 'b': 1, **x, **y}

Saídas:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z

Obrigado rednaw para edições.


No seu caso, o que você pode fazer é:

z = dict(x, **y)

Isto irá, como você quiser, colocar o dict final em z , e fazer com que o valor da chave b seja apropriadamente substituído pelo segundo ( y ) dict's value:

>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027

Se você usa o Python 3, é apenas um pouco mais complicado. Para criar z :

z1 = dict(x.items() + y.items())
z2 = dict(x, **y)

Seja pythonic. Use uma comprehension :

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (lambda f=x.copy(): (f.update(y), f)[1])()
>>> z
{'a': 1, 'c': 11, 'b': 10}

A melhor versão que eu poderia pensar enquanto não estava usando a cópia seria:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z4 = {}
z4.update(x)
z4.update(y)

É mais rápido que dict(x.items() + y.items()) mas não tão rápido quanto n = copy(a); n.update(b) n = copy(a); n.update(b) , pelo menos no CPython. Esta versão também funciona no Python 3 se você alterar iteritems() para items() , o que é feito automaticamente pela ferramenta 2to3.

Pessoalmente eu gosto desta versão melhor porque descreve razoavelmente bem o que eu quero em uma única sintaxe funcional. O único problema menor é que não torna completamente óbvio que os valores de y têm precedência sobre os valores de x, mas não acredito que seja difícil descobrir isso.


Isso provavelmente não será uma resposta popular, mas você quase certamente não quer fazer isso. Se você quiser uma cópia que seja uma mesclagem, use copy (ou deepcopy , dependendo do que quiser) e atualize. As duas linhas de código são muito mais legíveis - mais Pythonic - do que a criação de linha única com .items () + .items (). Explícito é melhor que implícito.

Além disso, quando você usa .items () (pré Python 3.0), você está criando uma nova lista que contém os itens do dict. Se os seus dicionários são grandes, isso é bastante sobrecarga (duas grandes listas que serão descartadas assim que o dict mesclado for criado). update () pode funcionar com mais eficiência, porque pode executar o segundo dict item por item.

Em termos de time :

from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))

IMO a pequena desaceleração entre os dois primeiros vale a pena pela legibilidade. Além disso, argumentos de palavras-chave para criação de dicionário foram adicionados apenas no Python 2.3, enquanto que copy () e update () funcionarão em versões mais antigas.





merge