Isso é menos uma pergunta sobre a natureza da digitação de patos e mais sobre permanecer pitônico, suponho.
Primeiro de tudo - ao lidar com ditados, em particular quando a estrutura do ditado é razoavelmente previsível e uma determinada chave normalmente não está presente, mas às vezes existe, primeiro penso em duas abordagens:
if myKey in dict:
do_some_work(dict[myKey])
else:
pass
E, claro, Ye Olde 'perdão versus permissão'.
try:
do_some_work(dict[myKey])
except KeyError:
pass
Como um viajante Python, sinto que vejo o último preferido, o que só me parece estranho, porque os documentos do Python try/excepts
parecem preferidos quando há um erro real, em oposição a um ... hum ... ausência de sucesso?
Se o ditado ocasional não tiver chave no myDict e for sabido que nem sempre terá essa chave, é uma tentativa / exceto contextualmente enganosa? Este não é um erro de programação, é apenas um fato dos dados - esse ditado simplesmente não tinha essa chave específica.
Isso parece particularmente importante quando você olha para a sintaxe try / except / else, que parece ser realmente útil quando se trata de garantir que a tentativa não esteja capturando muitos erros. Você é capaz de fazer algo como:
try:
foo += bar
except TypeError:
pass
else:
return some_more_work(foo)
Isso não levará a engolir todos os tipos de erros estranhos que provavelmente são resultado de algum código incorreto? O código acima pode estar impedindo você de ver que você está tentando adicionar 2 + {}
e você pode nunca perceber que alguma parte do seu código está terrivelmente errada. Eu não sugiro que devemos verificar todos os tipos, é por isso que é Python e não JavaScript - mas, novamente, com o contexto de try / except, parece que ele deve pegar o programa fazendo algo que não deveria estar fazendo. de permitir que ele continue.
Sei que o exemplo acima é uma espécie de argumento de palha e é de fato intencionalmente ruim. Mas, dado o credo pitônico de better to ask forgiveness than permission
que não posso ajudar, sinto que ele sugere a questão de onde a linha na areia está entre a aplicação correta de if / else vs try / except, especialmente quando você sabe o que esperar os dados com os quais você está trabalhando.
Não estou nem falando de preocupações com velocidade ou práticas recomendadas aqui, estou meio que confuso com o diagrama de Venn percebido de casos em que parece que poderia ser de qualquer maneira, mas as pessoas erram ao lado de uma tentativa / exceto porque 'alguém em algum lugar disse que era pitônico'. Eu tirei conclusões erradas sobre a aplicação desta sintaxe?
Respostas:
Use o método get :
... onde
default_value
está o valor devolvido sethe_key
não está nasome_dict
. Se você omitirdefault_value
,None
será retornado se a chave estiver faltando.Em geral, no Python, as pessoas tendem a preferir try / exceto do que verificar algo primeiro - consulte a entrada EAFP no glossário . Observe que muitas funções de "teste para associação" usam exceções nos bastidores.
fonte
dict
e fazendo um trabalho com base no que foi encontrado, parece queif myDict.get(a_key) is not None: do_work(myDict[a_key])
é mais prolixo e mais um exemplo de aparência implícita antes de saltar - além de ser um IMHO um pouco menos legível. Talvez eu não esteja entendendodict.get(a_key, a_default)
no contexto certo, mas parece que é um precursor para escrever 'não-mude-se-for-elses' ou valores mágicos. Eu gosto do que esse método faz, porém, analisarei mais profundamente.data = myDict.get(a_key, default)
edo_work
fará a coisa certa quando for dadodefault
(por exemploNone
) ou você fazif data: do_work(data)
. Apenas uma pesquisa é necessária em ambos os casos. (Pode ser queif data is not None: ...
, em ambos os casos, ainda seja apenas uma pesquisa e, em seguida, sua própria lógica possa assumir o controle).try/except/else
lixo horrível e apenas melhorou em geral o IMHO a legibilidade do meu código. Aprendi uma lição valiosa que já ouvi antes, mas que consegui deixar de levar em consideração: "Se você sente que está escrevendo muito código, pare e observe os recursos do idioma". Obrigado!!A chave ausente é uma regra ou uma exceção ?
De um ponto de vista pragmático, jogar / pegar é muito mais lento do que verificar se a chave está na tabela. Se falta uma chave é uma ocorrência comum - você deve usar a condição
Outra coisa a favor da condição é uma cláusula else - é muito mais fácil entender quando um dos blocos é executado, considere que mesmo a mesma classe de exceção pode ser lançada a partir de várias instruções no bloco try.
O código na cláusula exceto não deve fazer parte da falha normal (por exemplo, se a chave não estiver presente, adicione-a) - deve estar lidando com o erro.
fonte
try
/catch
mais rapidamente.No espírito de ser "pitônico" e, especificamente, digitar pato - a tentativa / exceção parece quase frágil para mim.
Tudo o que você realmente deseja é algo com acesso semelhante ao ditado, mas
__getitem__
pode ser substituído para fazer algo que não é o esperado. Por exemplo, usandodefaultdict
da biblioteca padrão:Como o valor de retorno padrão é Falsy, a verificação de acesso assim funciona na maioria das vezes muito bem. Parece manter o código mais simples também, e foi por isso que meus colegas de trabalho e eu o fizemos por meses.
Infelizmente, alguns meses depois, essas chaves extras acabaram causando problemas e erros difíceis de rastrear, porque
0
se tornaram um valor válido. E às vezes nós iria usarin
para verificar se uma chave existe, tornando o código de fazer coisas diferentes, quando deveria ter sido idêntico.A razão pela qual sugiro que pareça quebrada é porque, no espírito de digitação de pato do Python, tudo o que você deseja é algo parecido com um
defaultdict
ditado e se encaixa perfeitamente nesse requisito, como qualquer objeto que você possa criar que herdadict
. Você não pode garantir que o chamador não alterará sua implementação posteriormente, portanto, você deve fazer a coisa com menos efeitos colaterais.Use a primeira versão
if myKey in mydict
,.Além disso, observe que isso é especificamente sobre o exemplo da pergunta. O credo python de "Melhor pedir perdão do que permissão" tem como objetivo garantir que você realmente aja corretamente quando não conseguir o que deseja. Por exemplo, verificar se um arquivo existe e depois tentar lê-lo - pelo menos três coisas em que consigo pensar podem dar errado:
O primeiro em que você pode tentar "pedir permissão", mas, por natureza das condições de uma corrida, nem sempre funciona; o segundo é muito fácil esquecer de verificar; e o terceiro não pode ser verificado sem tentar ler o arquivo. De qualquer forma, o que você faz após a falha quase certamente será o mesmo; portanto, neste exemplo, é melhor "pedir perdão" usando uma tentativa / exceção.
fonte