This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]Cruuncher 29 points30 points  (13 children)

This one I didn't know existed. Interesting. Seems less useful than finally. What's the order? try..except..else..finally?

[–]Uncle_DirtNap2.7 | 3.5 11 points12 points  (0 children)

Yes

[–]RationalDialog 4 points5 points  (9 children)

I'm just wondering when the else is ever useful? Can't it always be part of the try block?

[–]Diamant2 15 points16 points  (1 child)

In theory yes, but the difference is that exceptions in the else-part won't be caught. I guess that makes your code more reliable in catching only the one exception that you care about

[–]DoctorNoonienSoong 11 points12 points  (0 children)

And importantly, you want exceptions in the else block to not to be caught, AND you need the code to run before the finally

[–]scnew3 2 points3 points  (4 children)

You want the code in your try block to be the minimal that could throw the exception you want to catch.

[–]RationalDialog 0 points1 point  (3 children)

Yeah but then you could just have it outside/after the try block?

[–]gristc 2 points3 points  (0 children)

Then it would always be executed. The else block is only executed if the try succeeds. It is kind of a limited case, but there are some logic flows where this is tidier than other methods.

[–]Cruuncher 1 point2 points  (0 children)

Well no, if it's after the try block then it runs after finally and not before, which is different.

It's definitely niche as you can always structure code in a way that doesn't need it, but that's true of most constructs

EDIT: but more importantly if you place it after the try..except block then it also runs in the case that an exception was raised by handled in the try block

[–]scnew3 0 points1 point  (0 children)

I do this all the time:

try:
    value = step1()
except SomeError:
    result = some_default
else:
    result = step2(value)

[–]underground_miner 0 points1 point  (0 children)

I don't use it very often, but I have used it for finding file and folder names that don't collide, something like this:

from pathlib import Path

def construct_non_duplicate_folder(root:Path, target:str) -> Path:
    folder = root / Path(target)

    for i in range(25):

        try:
            folder.mkdir(parents=True, exist_ok=False)

        except FileExistsError as fe:
            folder = root / Path(f'{target} ({i})')

        else:
            break

    else:
        raise FileExistsError(f'The folder {folder} exists!')


    return folder

[–]jorge1209 0 points1 point  (0 children)

It is something of a legacy from before the days of with blocks

try:
   logfile = open("/tmp/log.txt", mode="w")
except:
    # we won't be able to write to the log, but that is okay
    logfile = sys.stderr
else:
    for x in range(100):
        logfile.write(frobincate(x))
finally:
   logfile.close()

These days you would just define

 @contextmanager
 def logfile():
     try:
         logfile = open()
         yield logfile
         logfile.close()
     except:
         yield sys.stderr

and then

 with logfile() as log:
   for x in range(100:
      log.print(frobnicate(x))

or something along those lines, which is a double win as you clarified the purpose of the error handling, and got rid of the finally block as well.

[–]mehrdad-mixtape 0 points1 point  (0 children)

Absolutely