Vraag Het handmatig verhogen (gooien) van een uitzondering in Python


Hoe kan ik een uitzondering in Python verhogen zodat deze later via een except blok?


1516
2018-01-12 21:07


oorsprong


antwoorden:


Hoe kan ik handmatig een uitzondering in Python gooien / verhogen?

Gebruik de meest specifieke Exception-constructor die semantisch past bij uw probleem.

Wees specifiek in uw bericht, bijvoorbeeld:

raise ValueError('A very specific bad thing happened.')

Genereer geen generieke uitzonderingen

Vermijd het verhogen van een generieke uitzondering. Om het te vangen, moet je alle andere, meer specifieke uitzonderingen vangen die een subklasse hebben.

Probleem 1: bugs verbergen

raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.

Bijvoorbeeld:

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',)

Probleem 2: Zal ​​niet vangen

en meer specifieke vangsten vangen niet de algemene uitzondering op:

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

Praktische tips: raise uitspraak

Gebruik in plaats daarvan de meest specifieke Exception-constructor die semantisch past bij uw probleem.

raise ValueError('A very specific bad thing happened')

wat ook handig toestaat dat een willekeurig aantal argumenten aan de constructor wordt doorgegeven:

raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz') 

Deze argumenten zijn toegankelijk voor de args attribuut op het Exception-object. Bijvoorbeeld:

try:
    some_code_that_may_raise_our_value_error()
except ValueError as err:
    print(err.args)

prints

('message', 'foo', 'bar', 'baz')    

In Python 2.5, een echte message attribuut is toegevoegd aan BaseException ten gunste van het aanmoedigen van gebruikers om uitzonderingen onder te classificeren en te stoppen met gebruiken args, maar de introductie van message en de oorspronkelijke afschrijving van args is ingetrokken.

Praktische tips: except clausule

Wanneer u zich binnen een uitzonderingsclausule bevindt, wilt u misschien bijvoorbeeld loggen dat er een specifiek type fout is opgetreden en vervolgens opnieuw verhogen. De beste manier om dit te doen met behoud van het stacktrace is om een ​​blote raise-statement te gebruiken. Bijvoorbeeld:

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!

Wijzig uw fouten niet ... maar als u erop staat.

U kunt de stacktrace (en foutwaarde) behouden met sys.exc_info(), maar dit is veel meer foutgevoelig en heeft compatibiliteitsproblemen tussen Python 2 en 3, gebruik liever een kaal raise opnieuw verhogen.

Uitleggen - het sys.exc_info() geeft het type, de waarde en traceback terug.

type, value, traceback = sys.exc_info()

Dit is de syntaxis in Python 2 - merk op dat dit niet compatibel is met 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]

Als u wilt, kunt u wijzigen wat er gebeurt met uw nieuwe verhoging - bijvoorbeeld nieuwe args instellen voor de instantie:

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

En we hebben de hele traceback bewaard terwijl we de args aanpasten. Merk op dat dit zo is geen best practice en het is ongeldige syntaxis in Python 3 (waardoor het nog moeilijker is om de compatibiliteit te behouden).

>>> 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>

In Python 3:

    raise error.with_traceback(sys.exc_info()[2])

Nogmaals: vermijd handmatig manipulatie van tracebacks. Haar minder efficient en meer foutgevoelig. En als u threading en gebruikt sys.exc_info misschien krijgt u de verkeerde traceback (vooral als u uitzonderingsafhandeling gebruikt voor de controlestroom - die ik persoonlijk vaak zou vermijden).

Python 3, exception chaining

In Python 3 kun je uitzonderingen koppelen, die traceringen behouden:

    raise RuntimeError('specific message') from error

Let op:

  • deze doet staat het wijzigen van het opgewekte fouttype toe, en
  • dit is niet compatibel met Python 2.

Verouderde methoden:

Deze kunnen gemakkelijk worden verborgen en komen zelfs in productiecode terecht. U wilt een uitzondering maken, en door ze te doen, wordt een uitzondering gemaakt, maar niet de bedoeling!

Geldig in Python 2, maar niet in Python 3 is de volgende:

raise ValueError, 'message' # Don't do this, it's deprecated!

Enkel en alleen geldig in veel oudere versies van Python (2,4 en lager), je ziet misschien nog steeds mensen die snaren verhogen:

raise 'message' # really really wrong. don't do this.

In alle moderne versies zal dit feitelijk een TypeError veroorzaken, omdat u geen BaseException-type aan het verhogen bent. Als u niet controleert op de juiste uitzondering en geen recensent heeft die op de hoogte is van het probleem, kan deze in productie worden genomen.

Voorbeeldgebruik

Ik hef uitzonderingen op om consumenten van mijn API te waarschuwen als ze het verkeerd gebruiken:

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)))

Maak uw eigen fouttypen wanneer u wilt

"Ik wil expres een fout maken, zodat deze in de uitzondering valt"

U kunt uw eigen fouttypen maken. Als u wilt aangeven dat er iets mis is met uw toepassing, hoeft u alleen maar het juiste punt in de uitzonderingshiërarchie te subklasse:

class MyAppLookupError(LookupError):
    '''raise this when there's a lookup error for my app'''

en gebruik:

if important_key not in resource_dict and not ok_to_be_missing:
    raise MyAppLookupError('resource is missing, and that is not ok.')

1890
2018-06-05 16:30



DOE DIT NIET. Een kale opvoeden Exception is absoluut niet het juiste om te doen; zien Het uitstekende antwoord van Aaron Hall in plaats daarvan.

Kan niet veel meer pythonic krijgen dan dit:

raise Exception("I know python!")

Zien de documenten van de verhogingstekst voor python als je meer informatie wilt.


541
2018-01-12 21:08



Voor het gewone geval waarbij je een uitzondering moet maken als reactie op een aantal onverwachte omstandigheden en die je nooit van plan bent te vangen, maar gewoon snel faalt om je te laten debuggen als het ooit gebeurt - de meest logische lijkt te zijn AssertionError:

if 0 < distance <= RADIUS:
    #Do something.
elif RADIUS < distance:
    #Do something.
else:
    raise AssertionError("Unexpected value of 'distance'!", distance)

29
2018-05-19 04:55



In Python3 zijn er 4 verschillende syntaxes voor rasperuitzonderingen:

1. raise exception 
2. raise exception (args) 
3. raise
4. raise exception (args) from original_exception

1. verhoog uitzondering vs. 2. verhoog uitzondering (args)

Als je gebruikt raise exception (args)  om een ​​uitzondering te maken dan de args wordt afgedrukt wanneer u het uitzonderingsobject afdrukt, zoals in het onderstaande voorbeeld.

  #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 verklaring zonder argumenten herleeft de laatste uitzondering. Dit is handig als u enkele acties moet uitvoeren nadat u de uitzondering hebt opgevangen en deze vervolgens opnieuw wilt verhogen. Maar als er eerder geen uitzondering was, raise verklaring roept op TypeError Uitzondering.

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. verhoog exception (args) van original_exception

Deze instructie wordt gebruikt om uitzonderingsketens te maken waarin een uitzondering die wordt verhoogd in reactie op een andere uitzondering, de details van de oorspronkelijke uitzondering kan bevatten - zoals weergegeven in het onderstaande voorbeeld.

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__)

Output:

ZeroDivisionError --  division by zero
MyException Zero Division 
division by zero

22
2017-11-08 17:54



Lees eerst de bestaande antwoorden, dit is slechts een addendum.

Merk op dat je uitzonderingen kunt maken met of zonder argumenten.

Voorbeeld:

raise SystemExit

verlaat het programma maar u wilt misschien weten wat er is gebeurd. Dus u kunt dit gebruiken.

raise SystemExit("program exited")

dit zal "programma verlaten" naar stderr afdrukken voordat het programma wordt afgesloten.


5
2018-03-29 11:59