Chained exceptions in Python

Asked

Viewed 379 times

3

I am in doubt in a situation not so common but that I have seen some developers use that is the case of the string of exceptions.

I read the Python documentation about them but it was not as clear as Python acts behind the scenes in order to silence the first exception. If you could give me an example of code explained would be great.

Example:

Code:

try:
    1 / 0
except ZeroDivisionError:
    print("Exception: ZeroDivisionError")
    raise Exception from None
  • Can you ask the question an example of code that you have seen that generated this doubt? The way you asked, it was not clear.

  • You say several except by capturing several types of exceptions?

  • No. I mean when you raise a second exception in the treatment of another.

  • I have never seen anyone do that (with conscience ) and I see no reason to do it. Are you sure you saw it? Where?

  • https://docs.python.org/3/library/exceptions.html#built-in-exceptionss

  • Here are some explanations - https://stackoverflow.com/questions/13957829/how-to-use-raise-keyword-in-python

  • I know how to raise an exception the question refers to the chaining of the same

Show 2 more comments

1 answer

1


There’s not much mystery there: the "silencing" of an exception within an except is part of the way Python is made.

One always has to keep in mind that unlike compiled code, where an error in the program will put everything that is running in an invalid state, in Python, the execution of the program is under the control of the Python Runtime. An exception in running Python code is an object, like any other object - with its attributes and etc... what is different is that when an execution occurs (either because it happened, or because of a command raise), the interpreter for the execution of the Python code the point at which it is, and will return from all functions (technically, will pass to frames previous run) until you find an "except" block that matches the exception that occurred (if Try/except is at the same point where the exception occurred, it may not return from any function). At the point where except is, Python associates the exception object with a local variable (the one in except), and starts executing the block code except usually: at this point, the prorama is consistent, and "under control", not in an error condition. So much so that it is perfectly valid to simply put a pass within an except clause, to ignore an error (if we know that it is a type of temporary error that can happen from time to time and does not disrupt the operation of the program).

Already, if there is one raise from within the except, Python simply creates a new exception object, copies some data from the original exception object to this new one, and restarts the task of "going back" in the code until it finds a corresponding except. In the case of raise ...from None you esa explicitly saying not to take data from the original execution-would be the same as a raise Exception without the from.

The language does this. Now why do programmers put this in the code? This is perhaps a question of yours, and it is a question of the people who expressed themselves in the comments.

Let’s take the example of a web application running within a framework: the functions of the web application itself, such as views, are called when there is a web request that the framework directs to themselves - but they are not the "input port": the framework in general receives data on web requests, "dissects the url", and decides which view is called, arranges one or more internal objects (for example "request"), and then calls the application view. This is all Python code, within the framework. The Framework in general will call the view to the user within a "Try:/except" block; otherwise, any exception in the view would stop the framework server process (that is, error to serve a page, the whole server to -is not what you want in general - you want the server to continue serving other pages to other users and even to what found the error).

If this Try/except block of the framework intercepts an exception of which it knows nothing, it will generate an HTTP error "500". That is, it will look at your app settings, or use the default settings of the framework itself, and return to the browser the html that is set to when there is an 'error 500". It turns out that the framework in general will have exceptions of itself, which your application can use to indicate that it was not an error "500", but rather an error "404" or "403" (page not found or access denied), or any other error http (and both the framework and its application may want to use specific pages in that case).

So, if inside the code of your view, you will access the database and did not find the searched bojeto - or got some other error, the search may generate a IndexError (if you query the database, expect to have a result and have zero, for example) - if you let Indexerror "go up" to the code of the framework, you will get an error 500. But in the view code, you, when writing the code, know that if an "Indexerror" happens at that point, it is because the user, or another object was not found in the database - and, may want to show an "erro404" in the browser -

So there’s a natural pattern, something like

@view("/")
def minha_view(request):
    try:
        user = get_from_users(request.user)
    except IndexError as error:
        raise HTTPError404 from error

    # aqui continua o código para uma requisição bem sucedida
    ....

(In this case, the "Httperror404" would be an exception defined in the framework).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.