Mesclar dicionários é uma das operações mais comuns do Python. Python 3.9+ introduziu o| (mesclar) operador, tornando a abordagem mais limpa ainda mais limpa. Mas existem seis maneiras diferentes de mesclar dicionários, cada uma com comportamento diferente para chaves duplicadas, mutação e desempenho. Aqui estão todos os métodos explicados.
📋 Table of Contents
- Referência rápida: Visão geral de todos os métodos
- Método 1: | Operador (Python 3.9+ — Recomendado)
- Método 2: |= Para atualização local (Python 3.9+)
- Método 3: {**d1, **d2} Descompactando (Python 3.5+)
- Método 4: .update() para mutação no local
- Método 5: ChainMap — Visualização lenta sem copiar
- Comparação de desempenho
- Mesclagem profunda (dicionários aninhados)
- Perguntas Frequentes
- Conclusão
Referência rápida: Visão geral de todos os métodos
d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}
# 1. | operator (Python 3.9+) — RECOMMENDED for most cases
merged = d1 | d2 # {"a": 1, "b": 3, "c": 4}
# 2. |= operator — update d1 in-place (Python 3.9+)
d1 |= d2 # d1 is now {"a": 1, "b": 3, "c": 4}
# 3. ** unpacking — works in all Python 3.x
merged = {**d1, **d2} # {"a": 1, "b": 3, "c": 4}
# 4. .update() — in-place mutation
d1.update(d2) # d1 modified in-place, no return value
# 5. dict() constructor + unpacking
merged = dict(**d1, **d2) # {"a": 1, "b": 3, "c": 4}
# 6. ChainMap — lazy view of multiple dicts
from collections import ChainMap
merged = ChainMap(d1, d2) # ChainMap({'a':1,'b':2}, {'b':3,'c':4})
Método 1: | Operador (Python 3.9+ — Recomendado)
d1 = {"name": "Alice", "age": 30}
d2 = {"age": 31, "city": "Berlin"} # 'age' exists in both
result = d1 | d2
# {"name": "Alice", "age": 31, "city": "Berlin"}
# d2 values win on duplicate keys
# d1 is NOT modified — creates new dict
# Order matters: d2 | d1 would keep d1's age value
result_reversed = d2 | d1
# {"age": 30, "city": "Berlin", "name": "Alice"}
# d1 values win on duplicate keys
O| operador é limpo, legível e inequívoco sobre qual ditado vence os conflitos. Prefira isso para projetos Python 3.9+.
Método 2: |= Para atualização local (Python 3.9+)
config = {"debug": False, "timeout": 30}
overrides = {"debug": True, "max_connections": 100}
config |= overrides
# config is now {"debug": True, "timeout": 30, "max_connections": 100}
# Modifies config in-place — no new dict created
Usar|= quando você deseja atualizar um ditado existente com valores de outro. Equivalente aconfig.update(overrides) mas mais explícito sobre a semântica de mesclagem.
Método 3: {**d1, **d2} Descompactando (Python 3.5+)
defaults = {"color": "blue", "size": "medium"}
user_prefs = {"color": "red", "font": "arial"}
settings = {**defaults, **user_prefs}
# {"color": "red", "size": "medium", "font": "arial"}
# Advantage: can mix with literal keys
settings = {"version": "2.0", **defaults, **user_prefs, "modified": True}
# {"version":"2.0","color":"red","size":"medium","font":"arial","modified":True}
Mais útil ao construir um dict inline com substituições — comum para padrões de configuração. Um pouco menos legível que| para mesclagens simples, mas mais flexíveis em expressões.
Método 4: .update() para mutação no local
# Returns None — common mistake: assigned to variable
d1 = {"a": 1}
result = d1.update({"b": 2})
print(result) # None — NOT the merged dict!
print(d1) # {"a": 1, "b": 2} — d1 was mutated
# Correct usage:
d1 = {"a": 1}
d1.update({"b": 2, "a": 99}) # duplicate key: new value wins
print(d1) # {"a": 99, "b": 2}
Erro comum: Atribuindo o resultado de.update() para uma variável — ela retornaNone. Usar.update() somente quando você deseja alterar intencionalmente o primeiro ditado sem criar um novo.
Método 5: ChainMap — Visualização lenta sem copiar
from collections import ChainMap
defaults = {"color": "blue", "debug": False, "size": 10}
production = {"debug": True}
local = {"size": 20, "extra": "value"}
# ChainMap looks up keys in order (local first, then production, then defaults)
config = ChainMap(local, production, defaults)
print(config["debug"]) # True (from production)
print(config["color"]) # "blue" (from defaults)
print(config["size"]) # 20 (from local)
# No copy made — changes to source dicts are reflected
defaults["color"] = "green"
print(config["color"]) # "green" — live view
Melhor caso de uso: Camadas de configuração (local → ambiente → padrões) onde você deseja uma visualização ordenada por prioridade sem copiar dados. As pesquisas são O(n) onde n = número de dictos – evite pesquisas em grande escala.
Comparação de desempenho
import timeit, collections
d1 = {i: i for i in range(1000)}
d2 = {i: i*2 for i in range(500, 1500)}
# Python 3.11+ benchmarks (microseconds for 10,000 iterations)
print(timeit.timeit(lambda: d1 | d2, number=10000)) # 5.1µs
print(timeit.timeit(lambda: {**d1, **d2}, number=10000)) # 5.4µs
print(timeit.timeit(lambda: {**d1, **d2}, number=10000)) # 5.4µs
print(timeit.timeit(lambda: dict(d1, **d2), number=10000)) # 5.8µs
Todos os métodos create-new-dict estão dentro de 15% um do outro. Para operações no local,.update() e|= são mais rápidos, pois nenhum novo dict é alocado. A diferença de desempenho é insignificante para a maioria dos casos de uso – escolha com base na legibilidade.
Mesclagem profunda (dicionários aninhados)
# Standard merge doesn't deep-merge nested dicts
d1 = {"user": {"name": "Alice", "age": 30}}
d2 = {"user": {"email": "alice@example.com"}}
merged = d1 | d2
# {"user": {"email": "alice@example.com"}} — nested dict REPLACED not merged!
# Deep merge function
def deep_merge(base, override):
result = base.copy()
for key, value in override.items():
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
result[key] = deep_merge(result[key], value)
else:
result[key] = value
return result
merged = deep_merge(d1, d2)
# {"user": {"name": "Alice", "age": 30, "email": "alice@example.com"}} ✓
Perguntas Frequentes
P: Qual método devo usar no Python 3.9+?
R: Used1 | d2 para criar um novo ditado mesclado. Usard1 |= d2 para atualizações no local. Ambos são os mais pitônicos e legíveis no Python moderno.
P: O que acontece com chaves duplicadas?
R: Em todos os métodos padrão, o valor do dict mais à direita (último) vence. d1 | d2 — o valor de d2 vence. {**d2, **d1} — o valor de d1 vence. A ordem controla a precedência.
P: Como faço para mesclar dois dictos e manter ambos os valores para chaves duplicadas?
R: Use um defaultdict ou lógica manual:{k: [d1.get(k), d2.get(k)] for k in d1.keys() | d2.keys()}. Ou para mesclar listas: itere e use setdefault.
P: Existe uma linha única para vários dictos?
A: merged = {} | d1 | d2 | d3 cadeias mesclam operadores. Ou:from functools import reduce; merged = reduce(lambda a, b: a | b, [d1, d2, d3])
P: A mesclagem preserva o pedido de inserção?
R: Sim. Os dictos do Python 3.7+ mantêm a ordem de inserção. Nas mesclagens, as chaves aparecem em ordem: as chaves exclusivas de d1 e depois as chaves de d2 (incluindo duplicatas substituídas pelos valores de d2).
Conclusão
Para projetos Python 3.9+:usard1 | d2 para novos dictos mesclados ed |= other para atualizações no local. Para Python mais antigo ou ao construir expressões complexas:{**d1, **d2}. UsarChainMap para camadas de configuração sem copiar. Evitedict.update() quando você espera um valor de retorno – ele retornaNone e modificar dados no local geralmente é a escolha errada para código de estilo imutável.
🔗 Share this article
✍️ Leave a Comment