What is the purpose of using "Else" together with Try/except in Python?

Asked

Viewed 1,136 times

6

In Python, what’s the advantage of using else in a block try/catch?

If in this example below:

try:
    f = open('texto.txt', 'r')
except IOError:
    print('O arquivo não existe!')
else:
    print(f.read())
    f.close()

I do it this other way, without the else:

try:
    f = open('texto.txt', 'r')
    print(f.read())
    f.close()
except IOError:
    print('O arquivo não existe!')

It’s not the same?

2 answers

8


To this example may not make a difference, but for others yes.

The idea is always to keep the smallest possible code block inside the try you want to capture the exception. For example, imagine that you will make three function calls:

try:
    funcao1()
    funcao2()
    funcao3()
except ValueError as error:
    print(error)

If only one of the functions throws the exception, ok, you won’t have many problems. But what if the three can throw the same exception ValueError? How will you know what function launched it? You can analyze the traceback for that, but it’s an unnecessary job. If your action for when an exception is launched is the same, regardless of which function you launched, beauty, you also will not have problems with this form, but if you need to take different directions depending on who launched the exception will be complicated.

try:
    data = request_api_data()
    insert_in_database(data)
    send_mail()
except RuntimeError as error:
    print(error)

For example, you access an external API, take the desired data, save it to the database, and send an email notification. By way of example the three functions launch the exception RuntimeError in case of failure. You will probably want to take different steps if it is the API that is not responding, such as trying again later; if the problem is in the connection with the bank you would probably like to alert those responsible and if there is an error in sending e-mail you might even ignore. In the same except how to do this? Then:

try:
    data = request_api_data()
except RuntimeError as error:
    retry('5 minutes')
else:
    try:
        insert_in_database(data)
    except RuntimeError as error:
        notify_support()
    else:
        try:
            send_mail()
        except RuntimeError as error:
            pass

Obviously in this case, for being a rather random example, I ended up nesting many things, but in a real case you could simplify as your needs.

In short, inside the block try is only the part of the code that you want to treat the exception. That which can throw another untreated exception should stay out of the block - using the else if the exception does not redirect the application to another point in the code or outside the block try/except if it is safe.

6

Clause else the misunderstood and despised.

Always when we think about else associate immediately with blocks if, as Luciano Ramalho says in his book Python fluent, "The clause else is an underused feature of the language, it can be used not only in commands if, but also in commands for, while and try."

Try:

In the case of the use of else in try/except, the block else will only be executed if no exception is raised in the block try, according to the documentation, exceptions raised in the block else shall not be dealt with by the clauses execpt previous.

An example of Try block usage:

try: 
    chamada_arriscada()
    pos_chamada()
except OSError:
    log('OSError...')

Technically speaking the above code is not wrong, but put pos_chamada() inside the block try without good reason renders the code dubious and/or obscure, for the sake of clarity a block try should contain only commands that can generate exceptions, so it is best to do:

try: 
    chamada_arriscada()
except OSError:
    log('OSError...')
else:
    pos_chamada()

For:

The block else will only be executed after the end of the loop for, if there is an interruption by a break, for example, the block after the elsewill not be executed.

While:

Again the block elsewill not be executed if while is interrupted for a break, that is to say, elseshall be waived only if the while end on condition that it has become false.

If in either case an exception or a command return, break or continue occur and make the control exit the main loop, the clause elsewill be ignored.

Again quoting Luciano Ramalho, I agree with him when he says:

I think elsea poor choice of reserved word in all cases, except with if. It implies an exclusionary alternative, such as "perform this loop; otherwise, do that", but the semantics of else in loops is the opposite of this: "perform this loop, then do that". This suggests that then would be a better reserved word - and would also make sense in the context of Try: "Try this and then do that". However adding new reserved words can break a lot of existing code, and Guido avoids it as if it were a plague.

Note: Guido refers to Guido van Rossum, the creator of language.

Edited: Following @Guilherme Nascimento’s comment, I added examples and explanation for the links for and while. TL;DR

Preambulo for examples with for and while:

It is difficult to give a specific or "real" example, because it would be necessary to explain the context, so I created a generic example that may seem kind of "nonsense", but it is based on a real case. Let’s assume that we received a list of any operation that we will use later in our code, but first we need to normalize it (make each item between 0 and 1) if the number 7 nay appear in this list. For this, let’s first create the normalization function:

def normalize(lst):
    sum_lst = sum(lst)
    norm_lst = []
    for n in range(len(lst)):
        norm_lst.append(lst[n]/sum_lst)
    return norm_lst  

Now let’s create 2 lists one where appears the number 7 (in this case the function normalize nay should be called) and another where it does not appear.

lista1, lista2 = [1,2,3,6,7,9], [1,3,5,9,44,55]

Example with the use of for:

To be more practical, let’s define a function that receives the list and check if there is a presence of the element that avoids the call to normalization, in case the number 7 and then we test with the two lists created previously:

# Loop for
def test_for(lst):
    for item in lst:
        if item == 7:
            break
    else:
        return normalize(lst)
    return lst    

Testing with the list1:

test_for(lista1)

Exit:

[1, 2, 3, 6, 7, 9]

Note that as the main loop was interrupted by break (to lista1 has the number 7), the normalization function has not been called.

Testing with the Lista2:

test_for(lista2)

Exit:

[0.008547008547008548,
 0.02564102564102564,
 0.042735042735042736,
 0.07692307692307693,
 0.37606837606837606,
 0.4700854700854701]

Now as the lista2 does not contain the number 7, the loop for was executed to the end, testing all elements of the list and then the normalization function was called in the block after the else.

Example using the loop while:

Just like we did with for, let’s define a function to test the loop while:

# Loop While
def test_while(lst):
    n = 1
    while n <= len(lst)-1:
        if lst[n-1] == 7:
            break
        n+=1
    else:
        return normalize(lst)
    return lst

Testing with the lista1

test_while(lista1)

Exit:

[1, 2, 3, 6, 7, 9]

Again, as this list contains the number 7, the normalization function was not called, as the main loop (while) was not executed until the end, was interrupted by break in the penultimate item on the list.

Testing with the lista2:

test_while(lista2)

Exit:

[0.008547008547008548,
 0.02564102564102564,
 0.042735042735042736,
 0.07692307692307693,
 0.37606837606837606,
 0.4700854700854701]  

In this case the while loop was executed until the end, that is, until the variable n did not meet the condition of the loop n less than or equal to the number of elements in the list, that is, all elements in the list have been tested, then the clause else was executed.

See working on repl.it.

  • The explanation about for e while was sensational, already has my +1, I would ask you to add examples with "exit" explanation comments, would enrich and facilitate the understanding of who this started.

  • @Guilhermenascimento I created a fictional example, the "real" examples I have would be meaningless out of context, but I think I was able to elucidate a little more.

Browser other questions tagged

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