Estou escrevendo um módulo e quero ter uma hierarquia de exceções unificada para as exceções que ele pode gerar (por exemplo, herdar de uma FooError
classe abstrata para todas asfoo
exceções específicas do módulo). Isso permite que os usuários do módulo capturem essas exceções específicas e as tratem distintamente, se necessário. Mas muitas das exceções levantadas no módulo são geradas por causa de alguma outra exceção; por exemplo, falha em alguma tarefa devido a um OSError em um arquivo.
O que eu preciso é "agrupar" a exceção capturada, de modo que ela tenha um tipo e mensagem diferentes , para que as informações estejam disponíveis ainda mais na hierarquia de propagação por qualquer que seja a captura da exceção. Mas não quero perder o tipo, a mensagem e o rastreamento de pilha existentes; todas essas informações são úteis para alguém que tenta depurar o problema. Um manipulador de exceção de nível superior não é bom, pois estou tentando decorar a exceção antes que ela avance na pilha de propagação, e o manipulador de nível superior está muito atrasado.
Isso é parcialmente resolvido derivando os foo
tipos de exceção específicos do meu módulo do tipo existente (por exemplo class FooPermissionError(OSError, FooError)
), mas isso não facilita a quebra da instância de exceção existente em um novo tipo, nem modifica a mensagem.
PEP 3134 do Python "Encadeamento de exceções e rastreamentos incorporados" discute uma alteração aceita no Python 3.0 para "encadear" objetos de exceção, para indicar que uma nova exceção foi gerada durante o tratamento de uma exceção existente.
O que estou tentando fazer está relacionado: preciso também que ele funcione em versões anteriores do Python, e não para encadeamento, mas apenas para polimorfismo. Qual é a maneira certa de fazer isso?
fonte
except Exception as e
->raise type(e), type(e)(e.message + custom_message), sys.exc_info()[2]
-> esta solução é de outra questão SO . Isso não é bonito, mas funcional.Respostas:
O Python 3 introduziu o encadeamento de exceções (conforme descrito no PEP 3134 ). Isso permite, ao criar uma exceção, citar uma exceção existente como a "causa":
A exceção capturada, assim, se torna parte (é a “causa”) da nova exceção e está disponível para qualquer código que captura a nova exceção.
Ao usar esse recurso, o
__cause__
atributo é definido. O manipulador de exceção interno também sabe como relatar a "causa" e o "contexto" da exceção junto com o rastreamento.No Python 2 , parece que este caso de uso não tem uma boa resposta (conforme descrito por Ian Bicking e Ned Batchelder ). Vadio.
fonte
try: return 2 / 0 except ZeroDivisionError as e: raise ValueError(e)
Você pode usar sys.exc_info () para obter o rastreamento e criar sua nova exceção com o referido rastreamento (como o PEP menciona). Se você deseja preservar o tipo e a mensagem antigos, pode fazê-lo na exceção, mas isso só será útil se o que detectar a exceção a procurar.
Por exemplo
Claro, isso realmente não é tão útil. Se fosse, não precisaríamos desse PEP. Eu não recomendaria fazê-lo.
fonte
sys.exc_info()
do Python para @Devin. Ele diz: "Atribuir o valor de retorno do traceback a uma variável local em uma função que está manipulando uma exceção causará uma referência circular". No entanto, uma observação a seguir diz que, desde o Python 2.2, o ciclo pode ser limpo, mas é mais eficiente evitá-lo.Você pode criar seu próprio tipo de exceção que estende a exceção que você capturou.
Mas na maioria das vezes, acho que seria mais simples capturar a exceção, manipulá-la e
raise
a exceção original (e preservar o retorno) ouraise NewException()
. Se eu estivesse chamando seu código e recebesse uma de suas exceções personalizadas, esperaria que seu código já tenha tratado qualquer exceção que você teve que capturar. Portanto, eu não preciso acessá-lo pessoalmente.Edit: Eu encontrei esta análise de maneiras de lançar sua própria exceção e manter a exceção original. Não há soluções bonitas.
fonte
Eu também descobri que muitas vezes eu preciso de algum "empacotamento" para os erros gerados.
Isso incluía o escopo de uma função e, às vezes, quebra apenas algumas linhas dentro de uma função.
Criou um wrapper para ser usado a
decorator
econtext manager
:Implementação
Exemplos de uso
decorador
ao chamar o
do
método, não se preocupeIndexError
, apenasMyError
gerenciador de contexto
dentro
do2
, nocontext manager
, seIndexError
for levantado, será embrulhado e levantadoMyError
fonte
A solução mais direta para suas necessidades deve ser esta:
Dessa forma, você pode imprimir sua mensagem posteriormente e o erro específico gerado pela função de upload
fonte