аватар question@mail.ru · 01.01.1970 03:00

Retu operator in the Try/Except/Finally unit

There is such a function:

   def   f :   try :   1 / 0    experept :   retu   1    finally :   retu   2    3      

when starting it retus 2 , although after the exclusion the exception should fall into the experept block, where it is retued 1 Retu does not interrupt the function of the function?

аватар answer@mail.ru · 01.01.1970 03:00

Short answer: the block inside finally will be executed in any case, regardless of what happens inside the try, except, else blocks, so the value 2 will be retued>.


If you go deeper:

According to this, when the retu operator is encountered inside the try/except/else blocks, and then there is the finally operator, the function execution is not interrupted, but something like this happens:

  1. The retu value is remembered (but not retued), next, the execution flow proceeds to the finally block.
  2. All actions are performed inside the finally block, after which the previously stored value is retued.
  3. If the finally block contains its own retu, it overwrites the previous value and retus it, forgetting about everything that happened before.

But, it is important to mention that the "memorization" of the retued result occurs by copying its value to another variable (and then closing), and here, as in any other situation., the type of the object plays a role: mutable, or immutable.

Let's look at the code below:

def/span> f():    try:        a = 2        retu a    finally:        a += 11

As a result, the function retus 2, since numbers are in Python - immutable objects, the operation += creates a new object that does not affect the value copied to retu through retu.

But, let's change the situation:

def/span> f():    try:        a = [2]        retu a    finally:        a[0] += 1] += 1

Already here - the list [3] is retued because the value was changed by reference.

This happens because the lists - these are mutable objects, and as a result of operations with them, the same object is retued.


Is this behavior only for the retu statement?

In general, such an interruption of execution and transition to the finally block occurs not only with the retu operator, but also when any exception occurs, and many other things, such as calling sys.exit() (which, actually, also causes an exception).

Let's make sure of this:

def/span> f():    try:        raise Exception    finally:        retun>:        retu  1

As a result of the function, no exception will occur and 1 will be retued.

And if you think about it, this is a big problem, we will never know about the exception that we have., due to the value being retued in the finally block.

Therefore, in the code writing guide PEP 8 there is a special section in which it says that it is not recommended to use retu in the finally block, therefore: it is useful to know how it works, but It's not worth applying.

Use of the flow control statements retu/break/continue within the finally suite of a try...finally, where the flow control statement would jump outside the finally suite, is discouraged. This is because such statements will implicitly cancel any active exception that is propagating through the finally suite.


However, if an unhandled exception was initially thrown, and another one is thrown in the finally block., then both of them will be displayed.

def/span> f():    try:        raise Exception    finally:        raise TypeError TypeError

Error:

Traceback (most recent call last): File ""test.py "", line 2, in <module>    raise ExceptionExceptionDuring handling of the above exception, another exception occurred:Traceback (most recent call last):  File ""test.py"", line 4, in <module>    raise TypeErrorTypeError

rrorTypeError

Conclusions:

Summarizing all the above, we can understand that:

The finally operator is always executed, and it is executed in the last queue, so, if any exceptional situation occurs in the try-except-else block (value retu, exception, interrupt statements), then the code in the finally block may affect them (in case of a new exceptional situations).

But, of course, this applies to only one whole block (try-except-else-finally), and if we slightly changed the original example:

def/span> f():    retuass="">retu 3    try:        1 / 0    except:        except:        retu 1    1    finally:        retu 2

Then, of course, the function will already retu 3, because it won't have time to reach the exception block. after calling retu, its execution will be interrupted.

This behavior is only used with the finally operator, and for example, in the case of:

def/span> f():    try:        retuspan class="">retu 1    except:        pt:        retu 2    e    else:        retu 3

Despite the fact that there are no errors in the try block - the else block will fail, and the value 1 will be retued because the finally operator is missing, so the expected behavior with interrupting does not change.


Additionally

The functionality with guaranteed block execution finally is used implicitly and when using the context manager with, which is why it is often recommended to use: whatever happens inside the with block is a file closing operation./the connection will be made.

Latest

Similar