Ręczne podnoszenie (rzucanie) wyjątku w Pythonie
Jak mogę podnieść wyjątek w Pythonie, aby później mógł zostać przechwycony przez except
blok?
5 answers
Jak ręcznie wyrzucić / podnieść wyjątek w Pythonie?
Użyj najbardziej specyficznego konstruktora WYJĄTKÓW, który semantycznie pasuje do twojego problemu .
Bądź konkretny w swojej wiadomości, np.:
raise ValueError('A very specific bad thing happened.')
Nie podnoś ogólnych WYJĄTKÓW
Unikaj wprowadzania ogólnego wyjątku. Aby go złapać, musisz złapać wszystkie inne bardziej szczegółowe wyjątki, które go podklasują.
Problem 1: ukrywanie błędów
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
Dla przykład:
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',)
Problem 2: nie złapie
A bardziej szczegółowe połowy nie wyławiają ogólnego wyjątku:
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
Najlepsze praktyki: raise
oświadczenie
raise ValueError('A very specific bad thing happened')
, który również umożliwia przekazanie dowolnej liczby argumentów do konstruktora:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
Te argumenty są dostępne przez atrybut args
na wyjątku obiekt. Na przykład:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
Druki
('message', 'foo', 'bar', 'baz')
W Pythonie 2.5, atrybut message
został dodany do BaseException, aby zachęcić użytkowników do podklasowania wyjątków i zaprzestania używania args
, ale wprowadzenie message
i oryginalna deprecacja args została wycofana .
Najlepsze praktyki: except
klauzula
Gdy wewnątrz klauzuli except możesz na przykład zapisać, że wystąpił określony typ błędu, a następnie ponownie podnieść. Na najlepszym sposobem, aby to zrobić, zachowując ślad stosu, jest użycie instrukcji bare raise. Na przykład:
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!
Nie modyfikuj swoich błędów... ale skoro nalegasz.
Możesz zachować stacktrace (i wartość błędu) za pomocą sys.exc_info()
, ale jest to o wiele bardziej podatne na błędy i ma problemy ze zgodnością pomiędzy Pythonem 2 i 3, wolisz użyć gołego raise
do ponownego podniesienia.
Aby wyjaśnić - sys.exc_info()
zwraca typ, wartość i traceback.
type, value, traceback = sys.exc_info()
To jest składnia w Pythonie 2-uwaga to nie jest zgodne z Pythonem 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]
Jeśli chcesz, możesz zmodyfikować to, co dzieje się z nowym raise - np. ustawiając nowe args dla instancji:
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
I zachowaliśmy cały ślad podczas modyfikacji args. Zauważ, że jest to Nie najlepsza praktyka i jest to nieprawidłowa składnia w Pythonie 3 (co znacznie utrudnia zachowanie kompatybilności).
>>> 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>
W Python 3:
raise error.with_traceback(sys.exc_info()[2])
Ponownie: unikaj ręcznego manipulowania tracebackami. Jest mniej wydajny i bardziej podatny na błędy. A jeśli używasz wątków i sys.exc_info
, możesz nawet uzyskać niewłaściwy traceback (zwłaszcza jeśli używasz obsługi wyjątków do sterowania przepływem - czego osobiście chciałbym uniknąć.)
Python 3, łańcuchowanie WYJĄTKÓW
W Pythonie 3 można łączyć wyjątki, które zachowują Pakiety znaków:
raise RuntimeError('specific message') from error
Be świadomy:
- this does allow changing the error type raised, and
- to jest Nie kompatybilne z Pythonem 2.
Przestarzałe Metody:
Mogą one łatwo ukryć, a nawet dostać się do kodu produkcyjnego. Chcesz podnieść wyjątek, a ich wykonanie spowoduje wyjątek, ale nie ten zamierzony!
Ważne w Pythonie 2, ale nie w Pythonie 3 jest następujące:
raise ValueError, 'message' # Don't do this, it's deprecated!
Tylko ważne w znacznie starszych wersjach Pythona (2.4 i niższe), możesz nadal widzieć ludzi podnoszących ciągi:
raise 'message' # really really wrong. don't do this.
We wszystkich nowoczesnych wersjach spowoduje to wywołanie TypeError, ponieważ nie podnosisz typu BaseException. Jeśli nie sprawdzasz WŁAŚCIWEGO wyjątku i nie masz recenzenta, który byłby świadomy problemu, może on wejść do produkcji.
Przykładowe Użycie
Zgłaszam wyjątki, aby ostrzec konsumentów o moim API, jeśli go używają niepoprawnie:
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)))
Twórz własne typy błędów, gdy apropos
"nie jest to jednak żaden problem, ponieważ nie jest to możliwe.]}
Możesz tworzyć własne typy błędów, jeśli chcesz wskazać, że coś jest nie tak z Twoją aplikacją, po prostu podklasuj odpowiedni punkt w hierarchii WYJĄTKÓW:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
I użycie:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-28 20:07:54
NIE RÓB TEGO . Wychowanie nagiego
Exception
jest absolutnie nie właściwą rzeczą do zrobienia; zobacz doskonałą odpowiedź Aarona Halla .
Nie można uzyskać znacznie więcej pythonic niż to:
raise Exception("I know python!")
Zobacz dokumenty instrukcji raise dla Pythona, jeśli chcesz uzyskać więcej informacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:39
W powszechnym przypadku, w którym musisz rzucić wyjątek w odpowiedzi na nieoczekiwane warunki, i że nigdy nie zamierzasz go złapać, ale po prostu szybko zawieść, aby umożliwić Ci debugowanie stamtąd, jeśli to się kiedykolwiek stanie-najbardziej logicznym wydaje się AssertionError
:
if 0 < distance <= RADIUS:
#Do something.
elif RADIUS < distance:
#Do something.
else:
raise AssertionError("Unexpected value of 'distance'!", distance)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-19 04:55:14
W Python3 istnieją 4 różne składnie do dzielenia WYJĄTKÓW:
1. raise exception
2. raise exception (args)
3. raise
4. raise exception (args) from original_exception
1. podnieść wyjątek vs. 2. raise exception (args)
Jeśli użyjesz raise exception (args)
do wywołania wyjątku, to args
zostanie wydrukowane podczas drukowania obiektu wyjątku - jak pokazano w poniższym przykładzie.
#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
polecenie bez argumentów ponownie podnosi ostatni wyjątek.
Jest to przydatne, jeśli potrzebujesz wykonaj pewne działania po wyłapaniu wyjątku, a następnie chcesz go ponownie podnieść. Ale jeśli wcześniej nie było wyjątku, raise
oświadczenie podnosi TypeError
wyjątek.
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. raise exception (args) from original_exception
Ta instrukcja jest używana do tworzenia łańcucha WYJĄTKÓW, w którym wyjątek wywołany w odpowiedzi na inny wyjątek może zawierać szczegóły oryginalnego wyjątku - jak pokazano w przykładzie poniżej.
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__)
Wyjście:
ZeroDivisionError -- division by zero
MyException Zero Division
division by zero
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-26 10:00:38
najpierw Przeczytaj istniejące odpowiedzi, to tylko dodatek.
Zauważ, że możesz zgłaszać wyjątki z argumentami lub bez nich.
Przykład:
raise SystemExit
Wychodzi z programu, ale może chcesz wiedzieć, co happened.So możesz tego użyć.
raise SystemExit("program exited")
Wyświetli "program zakończony" na stderr przed zamknięciem programu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-02 12:59:25