Eu tenho uma pergunta sobre expressões idiomáticas e legibilidade, e parece haver um conflito de filosofias Python para este caso específico:
Quero construir o dicionário A a partir do dicionário B. Se uma chave específica não existir em B, não faça nada e continue.
Qual caminho é melhor?
try:
A["blah"] = B["blah"]
except KeyError:
pass
ou
if "blah" in B:
A["blah"] = B["blah"]
"Faça e peça perdão" vs. "simplicidade e clareza".
Qual é melhor e por que?
python
idioms
readability
defaultdict
code-readability
LeeMobile
fonte
fonte
if "blah" in B.keys()
, ouif B.has_key("blah")
.A.update(B)
não funcionar para você?has_key
tornou-se obsoleto em favor dein
e a verificaçãoB.keys()
muda uma operação O (1) para uma O (n)..has_key
está obsoleto ekeys
cria uma lista desnecessária em py2k e é redundante em py3kA = dict((k, v) for (k, v) in B if we_want_to_include(k))
.Respostas:
As exceções não são condicionais.
A versão condicional é mais clara. Isso é natural: é um controle de fluxo direto, que é para o que as condicionais são projetadas, não exceções.
A versão de exceção é usada principalmente como uma otimização ao fazer essas pesquisas em um loop: para alguns algoritmos, ela permite eliminar testes de loops internos. Não tem esse benefício aqui. Tem a pequena vantagem de evitar ter que dizer
"blah"
duas vezes, mas se você estiver fazendo muito disso, provavelmente deverá ter umamove_key
função auxiliar de qualquer maneira.Em geral, eu recomendo fortemente manter a versão condicional por padrão, a menos que você tenha um motivo específico para não fazê-lo. As condicionais são a maneira óbvia de fazer isso, o que geralmente é uma forte recomendação para preferir uma solução a outra.
fonte
"blah"
mais frequência, o que leva a uma situação mais sujeita a erros.Há também uma terceira maneira que evita exceções e pesquisa dupla, o que pode ser importante se a pesquisa for cara:
Caso você espere que o dicionário contenha
None
valores, você pode usar algumas constantes mais esotéricas comoNotImplemented
,Ellipsis
ou fazer uma nova:De qualquer forma, usar
update()
é a opção mais legível para mim:fonte
Pelo que entendi, você deseja atualizar o dict A com pares de chave e valor do dict B
update
é a melhor escolha.Exemplo:
fonte
A.update({k: v for k, v in B.iteritems() if k in specificset})
Citação direta do wiki de desempenho do Python:
Portanto, parece que ambas as opções são viáveis dependendo da situação. Para obter mais detalhes, você pode consultar este link: Try-except-performance
fonte
Acho que a regra geral aqui é que
A["blah"]
normalmente existirá, se sim, tente - exceto que é bom, se não, useif "blah" in b:
Acho que "experimentar" sai barato na hora, mas "exceto" é mais caro.
fonte
Acho que o segundo exemplo é o que você deve escolher, a menos que este código faça sentido:
Lembre-se de que o código será abortado assim que houver uma chave que não esteja em
B
. Se esse código fizer sentido, você deve usar o método de exceção; caso contrário, use o método de teste. Na minha opinião, por ser mais curto e expressar claramente a intenção, é muito mais fácil de ler do que o método de exceção.Claro, as pessoas que dizem para você usar
update
estão corretas. Se você estiver usando uma versão do Python que ofereça suporte a compreensão de dicionário, eu prefiro fortemente este código:fonte
for key in ["foo", "bar", "baz"]: try: A[key] = B[key]
A regra em outros idiomas é reservar exceções para condições excepcionais, ou seja, erros que não ocorrem no uso regular. Não sei como essa regra se aplica ao Python, já que StopIteration não deveria existir por essa regra.
fonte
Pessoalmente, inclino-me para o segundo método (mas usando
has_key
):Dessa forma, cada operação de atribuição tem apenas duas linhas (em vez de 4 com try / except), e quaisquer exceções que forem lançadas serão erros reais ou coisas que você perdeu (em vez de apenas tentar acessar as chaves que não existem) .
Acontece que (veja os comentários sobre sua pergunta)
has_key
está obsoleto - então acho que é melhor escrito comofonte
Começando
Python 3.8
, e a introdução de expressões de atribuição (PEP 572) (:=
operador), podemos capturar o valor da condiçãodictB.get('hello', None)
em uma variávelvalue
para verificar se não éNone
(poisdict.get('hello', None)
retorna o valor associado ouNone
) e então usá-lo dentro do corpo de a condição:fonte
Embora a ênfase da resposta aceita no princípio "olhe antes de pular" possa se aplicar à maioria das linguagens, mais python pode ser a primeira abordagem, com base nos princípios python. Sem mencionar que é um estilo de codificação legítimo em python. O importante é certificar-se de que você está usando o bloco try except no contexto correto e de seguir as práticas recomendadas. Por exemplo. fazer muitas coisas em um bloco try, capturar uma exceção muito ampla ou, pior, a cláusula bare except etc.
Veja a referência de documentos python aqui .
Além disso, este blog de Brett, um dos desenvolvedores principais, aborda a maior parte disso em breve.
Veja outra discussão do SO aqui :
fonte