Devo testar if
algo válido ou apenas try
fazê-lo e capturar a exceção?
- Existe alguma documentação sólida dizendo que uma maneira é preferida?
- É uma maneira mais pitônica ?
Por exemplo, devo:
if len(my_list) >= 4:
x = my_list[3]
else:
x = 'NO_ABC'
Ou:
try:
x = my_list[3]
except IndexError:
x = 'NO_ABC'
Algumas reflexões ...
PEP 20 diz:
Os erros nunca devem passar silenciosamente.
A menos que seja explicitamente silenciado.
O uso de um em try
vez de um deve if
ser interpretado como um erro passando silenciosamente? E se sim, você o está silenciando explicitamente usando-o dessa maneira, tornando-o correto?
Não estou me referindo a situações em que você só pode fazer as coisas de uma maneira; por exemplo:
try:
import foo
except ImportError:
import baz
if index in mylist
testa se o índice é um elemento da minha lista, não um índice possível. Você prefeririaif index < len(mylist)
.if/else
quetry/catch
Nesse caso específico, você deve usar algo totalmente diferente:
Porém, em geral: se você espera que o teste falhe com freqüência, use
if
. Se o teste for caro em relação a apenas tentar a operação e capturar a exceção, se falhar, usetry
. Se nenhuma dessas condições se aplicar, siga o que for mais fácil.fonte
O uso
try
eexcept
diretamente, e não dentro de umif
guarda, sempre deve ser feito se houver a possibilidade de uma condição de corrida. Por exemplo, se você deseja garantir a existência de um diretório, não faça o seguinte:Se outro encadeamento ou processo criar o diretório entre
isdir
emkdir
, você sairá. Em vez disso, faça o seguinte:Isso será encerrado apenas se o diretório 'foo' não puder ser criado.
fonte
Se for trivial verificar se algo falhará antes de você fazer isso, provavelmente você deve favorecer isso. Afinal, a construção de exceções (incluindo os rastreios associados) leva tempo.
Exceções devem ser usadas para:
break
não o leva longe o suficiente) ou ...Observe que, muitas vezes, a resposta real é "nem" - por exemplo, no seu primeiro exemplo, o que você realmente deve fazer é usar apenas
.get()
para fornecer um padrão:fonte
if 'ABC' in myDict: x = myDict['ABC']; else: x = 'NO_ABC'
na verdade, geralmente é mais rápido do que usarget
, infelizmente. Não estou dizendo que esse é o critério mais importante, mas é algo para estar ciente.if / else
etry / except
pode ter seu lugar mesmo quando existem alternativas específicas de caso, porque elas têm características de desempenho diferentes..get()
é a procura de atributo e a sobrecarga de chamada de função no nível Python; o uso de palavras-chave nos built-ins basicamente vai direto para C. Eu não acho que isso vai ficar muito mais rápido tão cedo. Em relação aif
vs.try
, o método read dict.get () retorna um ponteiro que possui algumas informações de desempenho. A proporção de acertos / erros importa (try
pode ser mais rápida se a chave quase sempre existir), assim como o tamanho do dicionário.Como os outros posts mencionam, isso depende da situação. Existem alguns perigos com o uso de try / exceto no lugar de verificar antecipadamente a validade dos seus dados, especialmente quando os são usados em projetos maiores.
por exemplo, suponha que você tenha:
O IndexError não diz nada sobre se ocorreu ao tentar obter um elemento de index_list ou my_list.
fonte
Usar
try
é reconhecer que um erro pode passar, que é o oposto de fazê-lo passar silenciosamente. Usarexcept
está fazendo com que não passe.O uso
try: except:
é preferido nos casos em que aif: else:
lógica é mais complicada. Simples é melhor que complexo; complexo é melhor que complicado; e é mais fácil pedir perdão do que permissão.O que "erros nunca devem passar silenciosamente" é o aviso, é o caso em que o código pode gerar uma exceção que você conhece e o design admite a possibilidade, mas você não projetou de maneira a lidar com a exceção. Silenciar explicitamente um erro, na minha opinião, seria algo semelhante a
pass
umexcept
bloco, o que deveria ser feito apenas com a compreensão de que "não fazer nada" realmente é o tratamento correto de erros na situação específica. (Essa é uma das poucas vezes em que sinto que um comentário em código bem escrito provavelmente é realmente necessário.)No entanto, no seu exemplo específico, nenhum é apropriado:
A razão pela qual todos estão apontando isso - mesmo que você reconheça seu desejo de entender em geral e a incapacidade de apresentar um exemplo melhor - é que etapas secundárias equivalentes existem de fato em muitos casos, e procurá-las é o primeiro passo para resolver o problema.
fonte
Sempre que você usa
try/except
para controlar o fluxo, pergunte a si mesmo:try
bloco é bem-sucedido e quando falha?try
bloco?try
bloco lança a exceção?try
bloco mudar, seu fluxo de controle ainda se comportará conforme o esperado?Se a resposta para uma ou mais dessas perguntas for 'não', pode haver muito perdão a ser solicitado; provavelmente do seu futuro eu.
Um exemplo. Recentemente, vi código em um projeto maior que se parecia com isso:
Conversando com o programador, constatou-se que o fluxo de controle pretendido era:
Isso funcionou porque
foo
fez uma consulta ao banco de dados e a consulta seria bem-sucedida sex
fosse um número inteiro e lançaria umaProgrammingError
sex
fosse uma lista.Usar
try/except
é uma má escolha aqui:ProgrammingError
,, não revela o problema real (quex
não é um número inteiro), o que dificulta a visualização do que está acontecendo.ProgrammingError
é gerado durante uma chamada de banco de dados, que perde tempo. As coisas ficariam realmente horríveis se acontecesse quefoo
algo gravasse no banco de dados antes de lançar uma exceção ou alterasse o estado de outro sistema.ProgrammingError
é gerado apenas quandox
há uma lista de números inteiros. Suponha, por exemplo, que haja um erro de digitação nafoo
consulta ao banco de dados. Isso também pode aumentar aProgrammingError
. A conseqüência é quebar(x)
agora também é chamado quandox
é um número inteiro. Isso pode gerar exceções enigmáticas ou produzir resultados imprevisíveis.try/except
bloco adiciona um requisito para todas as implementações futuras defoo
. Sempre que mudamosfoo
, devemos agora pensar em como ele lida com as listas e garantir que gera umProgrammingError
e não, digamos, umAttributeError
ou nenhum erro.fonte
Para um significado geral, considere ler Expressões idiomáticas e Anti-expressões idiomáticas em Python: Exceções .
No seu caso particular, como outros declararam, você deve usar
dict.get()
:fonte