Python "estender" para um dicionário


463

Qual é a melhor maneira de estender um dicionário com outro? Por exemplo:

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

Estou procurando por qualquer operação para obter esse forloop de prevenção :

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

Desejo fazer algo como:

a.extend(b)  # This does not work

25
Eu sabia que para listas [], então supose i pode ser trabalho para os outros, não Extrange ;-)
FerranB

Respostas:


695

6
Depois de ler os documentos, você entenderá por que existe uma 'atualização', mas não 'extensão'.
Georg

58
lembre-se de que update () modifica diretamente o dict e retorna None.
e18r

5
Mas e se você quiser apenas estender o ditado com valores que ainda não estão definidos (ou seja, não substituindo valores existentes)? Por exemplo, atualize um dict {"a":2, "b":3}com dict {"b":4, "c":5}para dict {"a":2, "b":3,"c":5}? É claro que é possível usando update()movendo algumas coisas ao redor, mas seria melhor se ele poderia ser realizado em apenas uma linha ...
Nearoo

17
@ Nearoo - simplesmente atualize o caminho oposto; em vez de x.update (y) [que iria substituir valores x com y], utilize y.update (x) [que substitui valores y com x] e utilize y como seu dict escolhida para outras operações
jonathanl

lembre-se de que updatesubstitui silenciosamente as entradas existentes. Ou seja, quaisquer valores em bsobrescrevem aqueles em achaves sobrepostas.
CGFoX 01/04

186

Uma bela jóia nesta questão encerrada :

O "caminho oneliner", alterando nenhum dos ditados de entrada, é

basket = dict(basket_one, **basket_two)

Aprenda o que **basket_two(o **) significa aqui .

Em caso de conflito, os itens de basket_twosubstituirão os de basket_one. No caso das falas simples, isso é bastante legível e transparente, e não tenho nenhum remorso em usá-lo sempre que um ditado que é uma mistura de outros dois for útil (qualquer leitor que tenha problemas para entender isso será realmente muito bem atendido). a maneira como isso o leva a aprender dicte o **formulário ;-). Então, por exemplo, usa como:

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

são ocorrências razoavelmente frequentes no meu código.

Originalmente enviado por Alex Martelli

Nota: No Python 3, isso funcionará apenas se todas as chaves do basket_two forem a string.


3
A documentação para dicté fácil de encontrar, enquanto **é um pouco mais complicada (a palavra-chave é kwargs ). Aqui está uma boa explicação: saltycrane.com/blog/2008/01/...
johndodo

4
isso pode ser usado para gerar uma segunda variável com um único comando, enquanto, basket_one.update(<dict>)como o nome disse, atualiza um dicionário existente (ou clonado).
Furins

2
Observe que no Python 3, os nomes dos argumentos e, portanto, as chaves de **anotherdict, devem ser cadeias de caracteres.
Petr Viktorin

Obrigado @johndodo - integrei suas sugestões no post.
precisa

1
Uma boa alternativa funcional para a resposta aceita. Essa abordagem é desejável se você precisar usar diretamente o ditado recém-combinado. (veja também o comentário de @ e18r na resposta aceita).
chinnychinchin

45

Você já tentou usar a compreensão de dicionário com o mapeamento de dicionário:

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

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

Outra maneira de fazer é usar dict (iterável, ** kwarg)

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

No Python 3.9, você pode adicionar dois dict usando union | operador

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

5
FYI: esta não é uma sintaxe válida em Python 2.7
ASAV Patel

2
Esta sintaxe é bastante nova (Python 3.5)
pianoJames

24
a.update(b)

Adicionará chaves e valores de b a a , substituindo se já houver um valor para uma chave.


17

Como outros já mencionaram, a.update(b)para alguns ditados ae balcançarão o resultado solicitado em sua pergunta. No entanto, quero ressaltar que muitas vezes vi o extendmétodo de mapear / definir objetos que, na sintaxe a.extend(b), aos valores de NÃO devem ser substituídos pelos bvalores de. a.update(b)sobrescreve aos valores e, portanto, não é uma boa opção paraextend .

Observe que alguns idiomas chamam esse método defaultsouinject , como pode ser considerado como uma maneira de injetar os valores de b (que podem ser um conjunto de valores padrão) em um dicionário sem substituir os valores que já possam existir.

Obviamente, você pode observar que a.extend(b)é quase o mesmo que b.update(a); a=b. Para remover a atribuição, você pode fazer o seguinte:

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)

Agradecemos a Tom Leys pela ideia inteligente de usar um dictconstrutor sem efeitos colaterais extend.


1

Você também pode usar as coleções do python.Chainmap, que foi introduzido no python 3.3.

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

Isso tem algumas vantagens possíveis, dependendo do seu caso de uso. Eles são explicados em mais detalhes aqui , mas darei uma breve visão geral:

  • Um mapa de cadeia usa apenas visualizações dos dicionários; portanto, nenhum dado é realmente copiado. Isso resulta em encadeamento mais rápido (mas pesquisa mais lenta)
  • Na verdade, nenhuma chave é substituída; portanto, se necessário, você sabe se os dados são de a ou b.

Isso principalmente o torna útil para coisas como dicionários de configuração.


0

Caso seja necessário como uma classe , você pode estendê-lo com dict e usar o método update :

Class a(dict):
  # some stuff
  self.update(b)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.