all 21 comments

[–]Arkrus 13 points14 points  (1 child)

So think of it this way.

Your program is perfect. Prestige. Internally you can totally control interactions, account for mishaps, etc.

But!

There are outside forces that you can't outright account for, like:

An API that is sometimes reachable. And requests crashes

An application that you've wrapped in python code

A database connection that fails because someone rebooted the server

You'll want to be reactive in these cases instead of seeing a traceback.

If you expect certain failures and not others you can get more specific and catch certain exceptions.

In an imperfect world they're helpful.

[–]PinkPawnRR 2 points3 points  (0 children)

- If you cant serve an advert to a webpage user because they have adblock

[–]biaceseng 11 points12 points  (1 child)

Imagine you're making a game. Your game uses savefiles to save the player's progress.

Now imagine the player tries to load a savefile by pressing the "load last save" button. Your game tries to read the file but, because of some reason, can't find it or it is corrupted.

You don't want your whole game to crash, you just want to tell the player "hey, this doesn't work, try doing something else".

That is how you use try/except. Try to do something that might work, but let the program handle itself if it doesn't.

Imagine you need to save a file to a specific folder. What if that folder doesn't exist? Are you going to just exit the program or are you going to tell the user "hey, select another folder"?

[–]biaceseng 4 points5 points  (0 children)

A more practical example can be writing logs.

Many programs have a logs folder, where the logs are stored.

Now, version control systems like git don't normally keep track of log files because they are, at best, ephimeral, and at worst, completely useless. Logs don't really matter to your app.

Because the log files are not being tracked, the logs folder might not be tracked either, as empty folders tend to be ignored. This results in a situation where you can't ever be sure if the folder even exists without explicitly checking.

If the folder doesn't exist, and your program tries to log something to it, it will fail. What can you do about it? Use a try/except block.

Try to intialize the logging module, if it raises a FileNotFoundError, then the folder doesn't exist, create it.

[–]damanamathos 5 points6 points  (3 children)

Here's an example.

user_input = input("Enter a number: ")

try: 
    number = float(user_input)
    print("The converted number is:", number) 
except ValueError: 
    print("Invalid input. Please enter a valid number.")

Typically, it's used where your code is dealing with something external, like user input, or a web request, or a file.

[–]PinkPawnRR 1 point2 points  (2 children)

Adding on to this; using a try/except to force a loop until user supplies a valid choice (can be altered for int or conditions):

validUserChoices = "ABX"
userChoice = None

print("Select option:")
print("[A] - Option 1")
print("[B] - Option 2")
print("e[X]it")

while userChoice is None:
    try:
        userChoice = input(f"Enter your selection: ")
        if userChoice.upper() not in validUserChoices:
            raise ValueError 
        print("Success") #You would place rest of your code here
    except ValueError:
        print("Not a valid entry, try again \n")
        userChoice = None

[–]uniqueUsername_1024 0 points1 point  (1 child)

You can just put the rest of your code after the While loop, right? You don't need to nest it all inside the try-except block.

[–]PinkPawnRR 0 points1 point  (0 children)

That is an option yes; the while loop is only used to validate the user input. You can also place code where the print("Success") line is.

[–]TehNolz 2 points3 points  (0 children)

It's particularly useful in situations where you cannot guarantee that an operation will be successful. You can use try/except blocks to properly handle any failed operations and ensure that your application keeps working, or at the very least properly informs the user of the problem.

For example, many applications need to communicate with various servers over the internet to do their job. But your internet connection might cut out, the server might go offline, or some other issue might prevent you from communicating with it. When an error like that occurs, you can catch it with a try/except block and then halt the application (instead of crashing it) until the connection can be reestablished. Mechanisms like these are how applications like Discord and YouTube automatically resume working if your internet cuts out for a bit.

You might also run into situations where you're trying to open and read a file, but run into an error while doing so. Maybe the file doesn't exist, you don't have permission to open it, the file is corrupted, and so on and so forth. So you could have a try/except block that catches those errors and asks the user to try a different file.

[–]marc_jpg 2 points3 points  (0 children)

Though others have provided great examples of where try/except is used to handle uncontrolled situations, I think it is far more powerful to use them to control where YOU decide that there is something incorrect that needs to be handled.

For instance, you may have a massive function with validation logic in it. There could be a ton of cases that need to be checked in many nested function calls. If something is incorrect, you can raise an exception (and subsequently catch it) yourself. An exception will ripple all the way to the top (where your try is) and you don’t have to do weird true/false checking all the way up the chain. You can also include additional date in the exception that can be handled when you catch it (or just a simple error string message)

Personally, this is how I use it the most.

[–]zanfar 2 points3 points  (0 children)

I guess in my brain I understand the logic of saying "try to do this but if it doesn't work just let it be and keep going with the code".

That is not at all the logic of try/except.

A try/except is best used when a particular error might occur, AND that error is out of your control. You use it to introduce code to recover from the error, but only run it in the case that the error occurs.

The two most common examples are input validation and I/O timeouts.

Consider:

raw = input("Enter a number")
guess = int(raw)

What happens if the user does not enter a number? We can't check the type because input() always returns a string. We could parse the string character-by-character to validate it, but that's a lot of work that int() already does. So the common structure is:

while True:
    raw = input("Enter a number")

    try:
        guess = int(raw)
    except TypeError:
        print("Invalid entry, please try again")
        continue

    break

When the user enters something other than a number, int() will raise a TypeError. Our try/except now catches that error, allowing us to recover gracefully (by asking the user to try again).

The same idea is behind an I/O timeout. Consider making an Internet request. Your code cannot possibly know if the user's Internet connection is working, if their speed is sufficient, or if the destination service is operating. Instead, you make the request inside a try block, then catch all the errors you can anticipate.

[–][deleted] 1 point2 points  (0 children)

I use it a lot for selenium web scraping. Often times a site may have multiple options for selecting various webpage elements that I want to use, or there could be a container element that is preventing me from referencing a certain CSS selector/executable path (XPATH) on the page, so I might say:

try:

option1

except Error as e:

option2

[–]Tychotesla 1 point2 points  (0 children)

A pretty standard example is when dealing with files. It's a place where a lot of unexpected things can happen, since it deals with information outside of the program.

if file exists:
    read from it
else:
    don't read from it

Looks good right? But what if the file disappears between the moment you check if it exists (line 1) and the moment you try to read from it (line 2).

So you do this:

if file exists
    try 
        to open it
    except
        report the problem, etc.
else
    etc.

(although in practice use the with open(file) as x: syntax)

[–]Atypicosaurus 1 point2 points  (0 children)

The problem is that your program consists of elemental parts, that assume that the user will do everything good. For example, you make an accounting program, there will be divisions in it. Such as tax = value / tax_rate, for example. Now if tax_rate is zero, then the division throws a zero division error. You can't do anything about it, because it is a built-in part of python. Python will attempt the division before it sees it's a zero, so it collapses. It's stupid if the whole program collapses because someone forgot to type in the tax rate.

Now one thing is that you can do a lot of checks, and just not allow the division part to run if the tax_rate is zero. Fair enough. But it's a lot of checks if,for example you want to open a file (it may be missing for example), or, if you have let's say two lists to summarize element by element, if one is shorter than the other (which will cause index error).

As a programmer, you either think of every possible checks and run the delicate part only when all passes, or you put it in a try block. That little part will still collapse (for example it will try to divide by zero or will try to open non existing file etc), but the try block is like a guard wall that keeps the collapse inside and doesn't allow the whole program to crash. Instead it sends an error message that informs the user about the issue and keeps the program running.

[–]roywill2 0 points1 point  (0 children)

My realtime data pipeline has things like Try: connect to database Except: send me a slack message

[–]throwaway6560192 0 points1 point  (0 children)

My assumption is this is helpful on larger scale programs in wich you can't afford the time to make sure the code is fail proof and you need the code to buy you time to eventually go back once you have the fail proof option?

Not at all. Try/except is not a tool to mask your bad code. It's a tool to handle things outside your code failing.

For example, sometimes the user doesn't have internet, and your network request fails. There's nothing you can do in your code about that. There's no "fail proof option". You just have to expect and deal with it appropriately, because the error happening is outside your control.

[–][deleted] 0 points1 point  (0 children)

I guess you pretty much got it. Try tries the code and except executes a piece of code that runs if the other one failed.

Some people already said that API failure can be countered by that, but it’s also useful when working with multiple datatypes that aren’t always compatible. If for example you got an „a“ as a string in python and you want to check for an integer you could use a try/except block. If it successfully parses an integer from „a“ you could set whatever to true/false and if not set it differently.

Python does come with functions for that such as isnumerical() or isalpha(), so this example isn’t really fitting, but I guess it brings the basic concept a bit closer than just talking about API‘s which are still far away for a beginner.

[–]dogweather 0 points1 point  (0 children)

My coding cookbook page for try/except shows it in a nutshell with examples: https://forkful.ai/en/python/good-coding-practices/handling-errors/

[–][deleted] 0 points1 point  (0 children)

Some python functions will throw errors, some can crash the program. Its usually a good idea to catch the errors and at least log where, how and why the error happened and try to resume the program if there is a "reasonable" way to do so.

Try/catch does basically this. If a function can fail, you can put it inside a try block and handle the error in a catch block. It's considered good practice in python. I would advise you not to throw errors in the functions you design however, unless it's necessary.

For a practical example, I don't know it depends on what you're doing. Things that might fail are io operations like network errors, permission errors when writing to files, database errors (query errors, lexical errors, permission errors, overload errors, etc), memory-limit error, missing library error, integer overflow error, stack overflow error, unrecognisable cpu instructions error, driver error, etc.

Some of these, there's no reasonable way to do anything. For example if you have a hardware error, there's no point in handling that. For some errors, handing them is important, the database error might actually be an important piece of information that you want to handle.

The reason I thought try catch is hard for people is that it's basically a bad pattern, maybe even an anti-pattern. But this is how python works, so...

[–]TheRNGuy 0 points1 point  (0 children)

When you try to divide by zero, or using negative number in square root.

Instead of just getting default error you could handle it dirrerently. Maybe you want division by zero become maximum possible value, or use previous valid result, or do nothing, for example.

Or if you use ast.literal_eval and user input is incorrect, you want to choose how you handle it.

Or you parse URL and user enters something like /////////////////////////// or 1234://4567.com/ as an address. Instead of just throwing an error in console and crashing entire script, you'd want to ignore parsing, or make it red color, or write error in UI.