Como posso gerar uma exceção no Python para que possa ser capturada posteriormente através de um except
bloco?
Como lançar / gerar manualmente uma exceção no Python?
Use o construtor Exception mais específico que se encaixa semanticamente no seu problema .
Seja específico na sua mensagem, por exemplo:
raise ValueError('A very specific bad thing happened.')
Evite criar um genérico Exception
. Para capturá-lo, você precisará capturar todas as outras exceções mais específicas que a subclasses.
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
Por exemplo:
def demo_bad_catch():
try:
raise ValueError('Represents a hidden bug, do not catch this')
raise Exception('This is the exception you expect to handle')
except Exception as error:
print('Caught this error: ' + repr(error))
>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)
E capturas mais específicas não capturam a exceção geral:
def demo_no_catch():
try:
raise Exception('general exceptions not caught by specific handling')
except ValueError as e:
print('we will not catch exception: Exception')
>>> demo_no_catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling
raise
declaraçãoraise ValueError('A very specific bad thing happened')
que também permite com facilidade um número arbitrário de argumentos serem passados para o construtor:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
Esses argumentos são acessados pelo args
atributo no Exception
objeto. Por exemplo:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
impressões
('message', 'foo', 'bar', 'baz')
No Python 2.5, um message
atributo real foi adicionado para BaseException
incentivar os usuários a subclassar Exceptions e parar de usar args
, mas a introdução message
e a descontinuação original de args foram retraídas .
except
cláusulaQuando dentro de uma cláusula de exceção, você pode, por exemplo, registrar que um tipo específico de erro ocorreu e, em seguida, aumentar novamente. A melhor maneira de fazer isso enquanto preserva o rastreamento da pilha é usar uma instrução bare raise. Por exemplo:
logger = logging.getLogger(__name__)
try:
do_something_in_app_that_breaks_easily()
except AppError as error:
logger.error(error)
raise # just this!
# raise AppError # Don't do this, you'll lose the stack trace!
Você pode preservar o stacktrace (e o valor do erro) sys.exc_info()
, mas isso é muito mais suscetível a erros e tem problemas de compatibilidade entre o Python 2 e 3 , prefere usar um nu raise
para aumentar novamente.
Para explicar - sys.exc_info()
retorna o tipo, valor e retorno.
type, value, traceback = sys.exc_info()
Esta é a sintaxe no Python 2 - observe que isso não é compatível com o Python 3:
raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
Se desejar, você pode modificar o que acontece com seu novo aumento - por exemplo, definindo novo args
para a instância:
def error():
raise ValueError('oops!')
def catch_error_modify_message():
try:
error()
except ValueError:
error_type, error_instance, traceback = sys.exc_info()
error_instance.args = (error_instance.args[0] + ' <modification>',)
raise error_type, error_instance, traceback
E preservamos todo o rastreamento enquanto modificamos os argumentos. Observe que essa não é uma prática recomendada e é uma sintaxe inválida no Python 3 (dificultando muito a solução da compatibilidade).
>>> catch_error_modify_message()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch_error_modify_message
File "<stdin>", line 2, in error
ValueError: oops! <modification>
No Python 3 :
raise error.with_traceback(sys.exc_info()[2])
Novamente: evite manipular manualmente os rastreamentos. É menos eficiente e mais propenso a erros. E se você estiver usando o encadeamento e sys.exc_info
poderá até obter o rastreamento errado (especialmente se estiver usando o tratamento de exceções para o fluxo de controle - o que eu pessoalmente evitaria).
No Python 3, você pode encadear exceções, que preservam os rastreamentos:
raise RuntimeError('specific message') from error
Estar ciente:
Eles podem facilmente ocultar e até entrar no código de produção. Você deseja criar uma exceção e, ao fazê-las, uma exceção, mas não a que se destina!
Válido no Python 2, mas não no Python 3 é o seguinte:
raise ValueError, 'message' # Don't do this, it's deprecated!
Válido apenas em versões muito mais antigas do Python (2.4 e inferior), você ainda pode ver pessoas criando strings:
raise 'message' # really really wrong. don't do this.
Em todas as versões modernas, isso realmente gera um TypeError
, porque você não está criando um BaseException
tipo. Se você não estiver verificando a exceção certa e não tiver um revisor ciente do problema, ele poderá entrar em produção.
Eu levanto Exceções para avisar os consumidores da minha API se eles a estiverem usando incorretamente:
def api_func(foo):
'''foo should be either 'baz' or 'bar'. returns something very useful.'''
if foo not in _ALLOWED_ARGS:
raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))
"Eu quero cometer um erro de propósito, para que ele entre na exceção"
Você pode criar seus próprios tipos de erro, se desejar indicar que algo específico está errado com seu aplicativo, basta subclassificar o ponto apropriado na hierarquia de exceções:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
e uso:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
raise
é o que eu precisava para poder executar a depuração de erro personalizada em vários níveis de execução de código sem interromper o rastreamento da pilha.raise sys.exc_info()[0], (sys.exc_info()[1], my_extra_info), sys.exc_info()[2]
parece fazer o que eu quero e nunca tive problemas com isso. Mas parece hacky, e não uma prática aceita. Existe uma maneira melhor?Exception
como sua classe pai - você pode subclassificar algo mais específico e deve fazê-lo se fizer sentido.AppError
exceção indefinida . Pode ser melhor usar um erroAttributeError
Não pode ficar muito mais pitônico do que isso:
Consulte os documentos da instrução raise para python, se desejar obter mais informações.
fonte
No Python3, existem 4 sintaxes diferentes para exceções de exclusão:
Se você usar
raise exception (args)
para gerar uma exceção,args
ela será impressa quando você imprimir o objeto de exceção - como mostrado no exemplo abaixo.raise
A instrução sem nenhum argumento gera novamente a última exceção. Isso é útil se você precisar executar algumas ações após capturar a exceção e depois desejar aumentá-la novamente. Mas, se não havia exceção antes, araise
instrução geraTypeError
Exception.Essa instrução é usada para criar o encadeamento de exceções, no qual uma exceção que é gerada em resposta a outra exceção pode conter os detalhes da exceção original - como mostrado no exemplo abaixo.
Resultado:
fonte
exception(args)
maisexception (args)
raise exception(args) from None
preciso dizer que a exceção atualmente ativa foi tratada e não é mais interessante. Caso contrário, se você criar uma exceção dentro de umexcept
bloco e ele não for tratado, os rastreamentos para ambas as exceções serão mostrados separados pela mensagem "Durante o tratamento da exceção acima, ocorreu outra exceção"Para o caso comum em que você precisa lançar uma exceção em resposta a algumas condições inesperadas e que nunca pretende capturar, mas simplesmente falhar rapidamente para permitir que você depure a partir daí, se isso acontecer - o mais lógico parece ser
AssertionError
:fonte
ValueError
queAssertionError
porque não há problema com uma afirmação (porque nenhuma está sendo feita aqui) - o problema é com um valor. Se você realmente deseja umAssertionError
neste caso, escrevaassert distance > 0, 'Distance must be positive'
. Mas você não deve verificar erros dessa maneira, porque as asserções podem ser desativadas (python -O
).-O
.Leia as respostas existentes primeiro, este é apenas um adendo.
Observe que você pode gerar exceções com ou sem argumentos.
Exemplo:
sai do programa, mas você pode querer saber o que aconteceu.
isto imprimirá "programa encerrado" para stderr antes de fechar o programa.
fonte
raise SystemExit()
seria a melhor escolha? Por que o primeiro funciona?Outra maneira de lançar uma exceção é
assert
. Você pode usar assert para verificar se uma condição está sendo cumprida, caso contrário, ela aumentaráAssertionError
. Para mais detalhes, dê uma olhada aqui .fonte
Apenas para observar: há momentos em que você deseja lidar com exceções genéricas. Se você estiver processando vários arquivos e registrando seus erros, poderá capturar qualquer erro que ocorra em um arquivo, registrá-lo e continuar processando o restante dos arquivos. Nesse caso, um
bloquear uma boa maneira de fazê-lo. Você ainda desejará
raise
exceções específicas para saber o que elas significam.fonte
Você deve aprender a instrução raise do python para isso. Deve ser mantido dentro do bloco try. Exemplo -
fonte