Respostas:
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 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 erro AttributeError
NÃO FAÇA ISSO . Levantar a nu não
Exception
é absolutamente a coisa certa a fazer; veja a excelente resposta de Aaron Hall .
Não pode ficar muito mais pitônico do que isso:
raise Exception("I know python!")
Consulte os documentos da instrução raise para python, se desejar obter mais informações.
No Python3, existem 4 sintaxes diferentes para exceções de exclusão:
1. raise exception
2. raise exception (args)
3. raise
4. raise exception (args) from original_exception
1. aumentar exceção vs. 2. aumentar exceção (args)
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 exception (args)
try:
raise ValueError("I have raised an Exception")
except ValueError as exp:
print ("Error", exp) # Output -> Error I have raised an Exception
#raise execption
try:
raise ValueError
except ValueError as exp:
print ("Error", exp) # Output -> Error
3.raise
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, a raise
instrução gera TypeError
Exception.
def somefunction():
print("some cleaning")
a=10
b=0
result=None
try:
result=a/b
print(result)
except Exception: #Output ->
somefunction() #some cleaning
raise #Traceback (most recent call last):
#File "python", line 8, in <module>
#ZeroDivisionError: division by zero
4. gerar exceção (args) de original_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.
class MyCustomException(Exception):
pass
a=10
b=0
reuslt=None
try:
try:
result=a/b
except ZeroDivisionError as exp:
print("ZeroDivisionError -- ",exp)
raise MyCustomException("Zero Division ") from exp
except MyCustomException as exp:
print("MyException",exp)
print(exp.__cause__)
Resultado:
ZeroDivisionError -- division by zero
MyException Zero Division
division by zero
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 um except
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
:
if 0 < distance <= RADIUS:
#Do something.
elif RADIUS < distance:
#Do something.
else:
raise AssertionError("Unexpected value of 'distance'!", distance)
ValueError
que AssertionError
porque não há problema com uma afirmação (porque nenhuma está sendo feita aqui) - o problema é com um valor. Se você realmente deseja um AssertionError
neste caso, escreva assert 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:
raise SystemExit
sai do programa, mas você pode querer saber o que aconteceu.
raise SystemExit("program exited")
isto imprimirá "programa encerrado" para stderr antes de fechar o programa.
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 .
def avg(marks):
assert len(marks) != 0,"List is empty."
return sum(marks)/len(marks)
mark2 = [55,88,78,90,79]
print("Average of mark2:",avg(mark2))
mark1 = []
print("Average of mark1:",avg(mark1))
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
try:
foo()
except Exception as e:
print(str(e)) # Print out handled error
bloquear uma boa maneira de fazê-lo. Você ainda desejará raise
exceções específicas para saber o que elas significam.
Você deve aprender a instrução raise do python para isso. Deve ser mantido dentro do bloco try. Exemplo -
try:
raise TypeError #remove TypeError by any other error if you want
except TypeError:
print('TypeError raised')
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.