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?

Author: DavidRR, 2010-01-13

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

Zamiast tego użyj najbardziej specyficznego konstruktora WYJĄTKÓW, który semantycznie pasuje do twojego problemu .

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.')
 2012
Author: Aaron Hall,
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 Exceptionjest 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.

 536
Author: Gabriel Hurley,
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)
 30
Author: Evgeni Sergeev,
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
 26
Author: N Randhawa,
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.

 6
Author: Anant Prakash,
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