Ao usar o PyCharm IDE, o uso de except:
sem um tipo de exceção aciona um lembrete do IDE de que essa cláusula de exceção é Too broad
.
Devo ignorar este conselho? Ou é Pythônico sempre especificar o tipo de exceção?
Ao usar o PyCharm IDE, o uso de except:
sem um tipo de exceção aciona um lembrete do IDE de que essa cláusula de exceção é Too broad
.
Devo ignorar este conselho? Ou é Pythônico sempre especificar o tipo de exceção?
Respostas:
Quase sempre é melhor especificar um tipo de exceção explícito. Se você usar uma except:
cláusula simples , poderá acabar capturando exceções diferentes das que espera detectar - isso pode ocultar bugs ou tornar mais difícil depurar programas quando eles não estão fazendo o que você espera.
Por exemplo, se você estiver inserindo uma linha em um banco de dados, talvez queira capturar uma exceção que indica que a linha já existe, para que possa fazer uma atualização.
try:
insert(connection, data)
except:
update(connection, data)
Se você especificar um bare except:
, também obterá um erro de soquete indicando que o servidor de banco de dados caiu. É melhor capturar apenas as exceções que você sabe como lidar - geralmente é melhor para o programa falhar no ponto da exceção do que continuar, mas se comportar de maneiras estranhas e inesperadas.
Um caso em que você pode querer usar um except:
servidor vazio é no nível superior de um programa que você precisa estar sempre em execução, como um servidor de rede. Mas então, você precisa ter muito cuidado para registrar as exceções, caso contrário, será impossível descobrir o que está errado. Basicamente, deve haver apenas no máximo um lugar em um programa que faça isso.
Um corolário de tudo isso é que seu código nunca deve funcionar raise Exception('some message')
porque força o código do cliente a ser usado except:
(ou o except Exception:
que é quase tão ruim). Você deve definir uma exceção específica para o problema que deseja sinalizar (talvez herdando de alguma subclasse de exceção embutida como ValueError
ou TypeError
). Ou você deve gerar uma exceção interna específica. Isso permite que os usuários do seu código sejam cuidadosos ao capturar apenas as exceções que desejam tratar.
except:
também pega (entre muitas outras coisas) NameError
e AttributeError
, então, se você digitar algo errado no try
bloco (por exemplo, sua função "inserir" é realmente chamada insert_one
porque alguém não valorizou a consistência tanto quanto deveria), sempre silenciosamente tenta update()
.
main()
)?
except Exception:
vai pegar NameError
e AttributeError
também. O que o torna except:
tão ruim é que ele captura coisas que não devem ser detectadas, por exemplo SystemExit
(levantadas quando você chama exit
ou sys.exit
, e agora você evitou uma saída intencional) e KeyboardInterrupt
(novamente, se o usuário clicar Ctrl-C
, você provavelmente não quer continuar correndo apenas para irritá-los). Apenas o último faz algum sentido real para ser capturado, e deve ser capturado explicitamente. Pelo menos except Exception:
permite que esses dois se propaguem normalmente.
Você não deve ignorar o conselho que o intérprete lhe dá.
Do Guia de estilo PEP-8 para Python:
Ao capturar exceções, mencione exceções específicas sempre que possível, em vez de usar uma cláusula exceto:.
Por exemplo, use:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
Uma simples exceção: cláusula capturará exceções SystemExit e KeyboardInterrupt, tornando mais difícil interromper um programa com Control-C, e pode disfarçar outros problemas. Se você quiser capturar todas as exceções que sinalizam erros de programa, use exceto Exceção: (bare except é equivalente a except BaseException :).
Uma boa regra prática é limitar o uso de cláusulas "exceto" a dois casos:
Se o handler de exceção for imprimir ou registrar o traceback; pelo menos o usuário saberá que ocorreu um erro. Se o código precisa fazer algum trabalho de limpeza, mas permite que a exceção se propague para cima com aumento. tente ... finalmente pode ser a melhor maneira de lidar com este caso.
Não é específico para Python isso.
O objetivo das exceções é lidar com o problema o mais próximo possível de onde ele foi causado.
Portanto, você mantém o código que poderia, em circunstâncias excepcionais, acionar o problema e a resolução "lado a lado".
O problema é que você não pode saber todas as exceções que podem ser lançadas por um trecho de código. Tudo o que você pode saber é que, se for uma exceção, digamos, um arquivo não encontrado, você pode interceptá-lo e solicitar que o usuário obtenha um que execute ou cancele a função.
Se você colocar try catch round that, então não importa o problema que houve em sua rotina de arquivo (somente leitura, permissões, UAC, não é realmente um pdf, etc), todos irão cair em seu arquivo não encontrado catch, e seu usuário está gritando "mas está aí, esse código é uma porcaria"
Agora, há algumas situações em que você pode pegar tudo, mas elas devem ser escolhidas conscientemente.
Eles são pegos, desfazem alguma ação local (como criar ou bloquear um recurso, (abrir um arquivo no disco para escrever, por exemplo), então você lança a exceção novamente, para ser tratada em um nível superior)
O outro você é que você não se importa por que deu errado. Imprimindo, por exemplo. Você pode ter uma pegadinha que diz: Há algum problema com sua impressora, resolva-o e não elimine o aplicativo por causa disso. De forma semelhante, se o seu código executasse uma série de tarefas separadas usando algum tipo de programação, você não gostaria que tudo morresse, porque uma das tarefas falhou.
Nota Se você fizer o acima, não posso recomendar algum tipo de registro de exceção, por exemplo, tente catch log end, altamente suficiente.
Você também pegará, por exemplo, Control-C com isso, então não faça isso a menos que "jogue" novamente. No entanto, nesse caso, você deve preferir usar "finalmente".
Sempre especifique o tipo de exceção, existem muitos tipos você não quiser pegar, como SyntaxError
, KeyboardInterrupt
, MemoryError
etc.
except Exception:
evitaria os tipos acima que não queremos capturar?
except Exception
está bem.
except Exception
pega SyntaxError
e MemoryError
porque é sua classe base. KeyboardInterrupt
, SystemExit
(gerado por sys.exit()
) não são capturados (são subclasses de BaseException imediatas)
Aqui estão os lugares onde eu uso, exceto sem tipo
Esse é o principal uso em meu código para exceções não verificadas
Eu sempre adiciono isso, para que o código de produção não espalhe rastreamentos de pilha
Tenho duas maneiras de fazer isso:
Eu prefiro assim, acho mais fácil detectar quais exceções deveriam ter sido capturadas apropriadamente: eu "vejo" melhor o problema quando uma exceção de nível inferior é registrada por um nível superior
Alguns colegas de trabalho preferem assim, pois mantém exceções de nível inferior nas funções de nível inferior, onde "pertencem".
Experimente isto:
try:
#code
except ValueError:
pass
Obtive a resposta neste link, se mais alguém tiver esse problema, dê uma olhada