Existe uma justificativa para decidir qual try
ou quais if
construções usar ao testar a variável para ter um valor?
Por exemplo, há uma função que retorna uma lista ou não retorna um valor. Quero verificar o resultado antes de processá-lo. Qual das alternativas a seguir seria mais preferível e por quê?
result = function();
if (result):
for r in result:
#process items
ou
result = function();
try:
for r in result:
#process items
except TypeError:
pass;
Respostas:
Você costuma ouvir que o Python incentiva o estilo EAFP ("é mais fácil pedir perdão do que permissão") sobre o estilo LBYL ("veja antes de pular"). Para mim, é uma questão de eficiência e legibilidade.
No seu exemplo (digamos que, em vez de retornar uma lista ou uma sequência vazia, a função retornasse uma lista ou
None
), se você espera que 99% do temporesult
realmente contenha algo iterável, eu usaria atry/except
abordagem. Será mais rápido se as exceções forem realmente excepcionais. Seresult
forNone
mais de 50% do tempo, o usoif
provavelmente será melhor.Para suportar isso com algumas medidas:
Portanto, enquanto uma
if
declaração sempre lhe custa, é quase livre configurar umtry/except
bloco. Mas quandoException
realmente ocorre, o custo é muito maior.Moral:
try/except
no controle de fluxo,Exception
s são realmente excepcionais.Nos documentos do Python:
fonte
try/except
foi 25% mais rápido do queif key in d:
nos casos em que a chave estava no dicionário. Era muito mais lento quando a chave não estava no dicionário, como esperado, e consistente com esta resposta.1/1
com timeit não é uma ótima opção, porque elas serão otimizadas (vejadis.dis('1/1')
e observe que nenhuma divisão ocorre).Sua função não deve retornar tipos mistos (ou seja, lista ou sequência vazia). Ele deve retornar uma lista de valores ou apenas uma lista vazia. Então você não precisaria testar nada, ou seja, seu código é recolhido para:
fonte
Ignore minha solução se o código que forneço não for óbvio à primeira vista e você precisar ler a explicação após o exemplo de código.
Posso assumir que o "nenhum valor retornado" significa que o valor de retorno é Nenhum? Se sim, ou se "no value" for False em termos de booleano, você pode fazer o seguinte, pois seu código trata essencialmente "no value" como "não iterate":
Se
function()
retornar algo que não é True, você itera sobre a tupla vazia, ou seja, não executa iterações. Isto é essencialmente LBYL.fonte
Seu segundo exemplo está quebrado - o código nunca lançará uma exceção TypeError, pois você pode percorrer as strings e as listas. A iteração através de uma string ou lista vazia também é válida - ele executará o corpo do loop zero vezes.
fonte
Look Before You Leap é preferível neste caso. Com a abordagem de exceção, um TypeError poderia ocorrer em qualquer lugar do corpo do loop e seria pego e jogado fora, o que não é o que você deseja e tornará a depuração complicada.
(Porém, concordo com Brandon Corfman: retornar Nenhum para 'sem itens' em vez de uma lista vazia está quebrado. É um hábito desagradável de codificadores Java que não devem ser vistos em Python. Ou Java.)
fonte
Geralmente, a impressão que tive é que as exceções devem ser reservadas para circunstâncias excepcionais. Se o
result
esperado é que nunca fique vazio (mas pode ser, se, por exemplo, um disco travou, etc.), a segunda abordagem faz sentido. Se, por outro lado, um vazioresult
é perfeitamente razoável em condições normais, testá-lo com umaif
declaração faz mais sentido.Eu tinha em mente o cenário (mais comum):
em vez do equivalente:
fonte
++
não funciona em python, use-a+= 1
.bobince sabiamente ressalta que agrupar o segundo caso também pode capturar TypeErrors no loop, o que não é o que você deseja. Se você realmente deseja usar uma tentativa, pode testar se é iterável antes do loop
Como você pode ver, é bastante feio. Eu não sugiro, mas deve ser mencionado para ser completo.
fonte
None
, sempre verifique o resultado comis None
ouis not None
. Por outro lado, também é péssimo criar exceções para obter resultados legítimos. Exceções são para coisas inesperadas. Exemplo:str.find()
retorna -1 se nada for encontrado, porque a própria pesquisa concluída sem erros.No que diz respeito ao desempenho, usar o bloco try para código que normalmente não gera exceções é mais rápido do que usar a instrução if toda vez. Portanto, a decisão depende da probabilidade de casos excecionais.
fonte
Como regra geral, você nunca deve usar try / catch ou qualquer exceção para manipular itens para controlar o fluxo. Mesmo que a iteração dos bastidores seja controlada através do aumento de
StopIteration
exceções, você ainda deve preferir seu primeiro trecho de código ao segundo.fonte