Try and Except in Layman's terms
Tags: python, errors, backenddevelopment
Published: 2023-09-04 14:59:18

In Nigerian local parlance, we say things like "coding sweet but na error kill am" meaning that coding is interesting but errors are its undoing...

What is software engineering without errors though? So errors are bound to occur in whatever project you are working on. No matter your level of expertise, there are moments when errors will humble you and bring you to your knees; That is why we have a concept called ERROR HANDLING.

In Python, there are three major types of errors. As a developer, It is either you are encountering a syntax error, a runtime error, or a logical error. Understanding these 3 Major types of errors will help you debug your errors faster

**SYNTAX ERRORS**
Whenever you see a syntax error blablabla.... just know that you have violated a rule in Python. for instance-

```
def helloworld()
    print("Hello World")

helloworld()

```
`
The above code is going to throw a syntax error because you forgot to put a double colon ":" while defining the Helloworld function. So you are the one that broke the Python syntax rule.

**RUNTIME ERRORS**
This error occurs when your logic is 'wack', you did not break any syntax rule, but your logic is incorrect, for instance- in Python or programming you cannot divide any number by zero, if you do, it will throw what is called the ZeroDivisionError.
`

```
num = 10/0
print(num)
```
`

In programming, you can't do the above, This logic is unacceptable, so it is going to throw a zeroDivisionError which falls under the Runtime Error.

Other examples of runtime errors are as follows:

- **TypeError**: This occurs when you are trying to perform a certain operation on the wrong data type

`

```
 username = "codechief"
  usernameGroup = username + 2
  print(username)
```
`
The above code snippet will throw a typeError because the variable username is a string, while the action you are trying to perform (username + 2) is only performed on an integer.



- **IndexError**
 will occur when you try to access an imaginary index, i.e. A list contains 5 elements, but you are trying to access the index of the 7th element... This will never fly.

`

```
 gender = ["boy", 'girl'] 
  singleGender = gender[4]
  print(singleGender)
```
`
The above code snippet will throw an error, the length of our list item is 2, but you are trying to access the 4th element.



- **KeyError**: Occurs when trying to access a dictionary key that doesn't exist.

`

```
car_color = {"volovo": "red"}
  singleCarColor = car_color['jeep']
  print(singleCarColor)
```
`
The above code snippet will throw a KeyError because Jeep does not exist in the car_color dictionary



- **NameError**: Arises when a variable or name is used without being defined.

`

```
 def fullname():
      print(lastname)
```
`
The above code snippet will throw a NameError because lastname was not defined or assigned any value before the point where it is being printed out.



- **FileNotFoundError**: This occurs when trying to open a file that doesn't exist.

**LOGICAL ERRORS**
Also known as semantic errors, these errors do not cause the program to crash or raise any error at all, you won't just get the desired result. logical errors are caused by flawed program logic; You need meticulousness to debug and fix these kinds of errors because it displays no error message whatsoever, but your program will just refuse to behave as expected.

Now that we understand the major types of errors that we have. Let's look at one of the ways by which we can handle some of these errors.

TRY and EXCEPT blocks are used to catch and handle errors that may occur during the execution of a code block.

What do I mean by this? There are some errors that you anticipate. i.e. you know that there is a probability of this particular block of code throwing an error, so you use the Try and Except block to catch the error.

`

```
import urllib.request

def network(): 
    response = urllib.request.urlopen('http://www.google.com', timeout=1)
    return "You are online."

network()
if __name__ == "__main__":
    result = network()
    print(result)
```
`
The code above defines a function named network that checks whether your internet connection is available by attempting to open a connection to the Google website (http://www.google.com).

If you are connected to the internet, it returns " You are online" but if you are offline, or when you try to put off your internet connection; it generates this truckload of errors as seen below-


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zf9ugsuzf5w1u0e53vh5.jpg)
Now, let us introduce the try and except block to the same lines of code

`

```
import urllib.request
def network():
    try:
        response = urllib.request.urlopen('http://www.google.com', timeout=1)
        return "You are online"
    except Exception as e:
        return "error: {}".format(e)

network()
if __name__ == "__main__":
    result = network()
    print(result)

```
`
Disconnect your internet and you will get this error-

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4tjg7wmhowajln2d1p1d.jpg)
Between the first error and the second error, you can agree with me that the second error looks less intimidating and less daunting. But that is not the catch; The Try and Except block is so helpful because you get to customise your errors however you want. you can use the Try and Except block to design your own error message that is short, clear, and concise.

So instead of getting this error: <urlopen error [Errno 11001] getaddrinfo failed> that doesn't help anyone or point to where the error is coming from. you get to customise it to something like 'you are offline' or any message of your choice.

Take a look at this:

`

```
import urllib.request
def network():
    try:
        response = urllib.request.urlopen('http://www.google.com', timeout=1)
        return "You are online"
    except Exception as e:
        return "You are offline"

network()
if __name__ == "__main__":
    result = network()
    print(result)
```
`

When you run the above lines of code while your internet is disconnected, you get a more friendly error message that was designed by you.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e5agwkvo0ss6ftgzlglm.jpg)
I hope you can see the difference between when You use the Try and Except block and when you do not.

Some of the advantages of using the Try and Except Block are as follows:

Program robustness: Try and Except block will prevent your program from stopping abruptly at the sight or encounter of an error. it handles errors gracefully. It helps to provide appropriate feedback, it gives you a whole lot of clues as to where the bug is in your code.

**Debugging:** Exception messages often provide valuable information about what went wrong, where it went wrong, and even how it went wrong in your code.

**User-Friendly**: Exception messages can be used to create a user-friendly experience for users. it points them to what is wrong, or the next step to take.

**Testing**: Are you a serious developer if you do not write unit tests for your code? Your guess is as good as mine; Exceptions make it easier to write unit tests. You can simulate different error scenarios and ensure that your code handles them correctly.

**Control Flow**: Exceptions can be used to make conditional statements in place of 'Ifs' and Else statements when trying to figure out the possibilities of an error occurring.

**When To Use Try and Except**

**Use the Try and Except Block When working with external resources** like files, network connections, or database connections, you should use try and except blocks to ensure that these resources are properly closed or released, even if an error occurs. eg.

`

```
try:
     file = open("example.txt", "r")
     data = file.read()
 except FileNotFoundError:
     print("The file does not exist.")
 finally:
     file.close()
```
`
The above lines of code can be interpreted as doing the following-

**Step 1**: TRY and open this file

**Step 2**: Read the contents of the file,

**Step 3**: Peradventure the file is not found or does not exist, raise an exception or please print the words 'The file does not exist'

**Step 4**: Finally! After all is said and done, close the file if you found the file or not.

**Use the Try and Except Block When taking user input** : You can use try and except to validate and handle input errors, ensuring that your program doesn't crash due to invalid user input. As A developer, the last person to trust is your users, You cannot trust them to always input the correct data at all times, even when there are clear instructions on what to input. You will still find rule breakers, so you have to prepare for them.

`

```
try:
     file = open("example.txt", "r")
     data = file.read()
 except FileNotFoundError:
     print("The file does not exist.")
 finally:
     file.close()
```
`
The above sample code attempts to get the user's age as input and convert it to an integer. If the user enters something that cannot be converted to an integer (e.g., a non-numeric string like John, or Mary), it catches the ValueError exception and displays an error message to inform the user that they need to enter a valid integer or number. This helps prevent your program from crashing due to invalid input and provides a better user experience by handling errors gracefully.

**Use The Try and Except Block when you need to make Network and External API Calls:** When making network requests or accessing external APIs, use try and except to handle network-related errors, such as timeouts or connectivity issues.

`

```
 import requests

 try:
     response = requests.get("https://www.google.com/")
     response.raise_for_status()  # Check for HTTP error status codes
 except requests.exceptions.RequestException as e:
     print(f"An error occurred: {e}")
```
`
The above code snippet demonstrates how to use the requests library to make an HTTP request to a URL and handle potential errors that might occur during the request. By using the try and except blocks, it ensures that the program doesn't crash due to network issues or HTTP errors and provides feedback to the user or logs the error for debugging purposes.

**Use the Try and Except Block when you want to carry out file operations** : When reading, writing, or manipulating files, use try and except blocks to handle file-related errors like file not found or permissions issues.

`

```
try:
     with open("books.txt", "r") as file:
         content = file.read()
 except FileNotFoundError:
     print("The file does not exist.")
```
`
The above code is used to open and read the contents of a file named "books.txt." If the file does not exist or there is any other issue when opening the file, it catches the FileNotFoundError exception and prints an error message.

**Use the Try and Except Block when carrying out Database Operations**: When working with databases, use try and except to handle database-related errors such as connection issues or SQL query errors.

`

```
import sqlite3

try:
    conn = sqlite3.connect("mydb.db")
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM Users")
except sqlite3.Error as e:
    print(f"Database error: {e}")
finally:
    conn.close()
```
`
The above code snippet is a basic example of using the sqlite3 module to connect to an SQLite database, perform a query that may result in an error (table not found), handle the database-related error using a try and except block, and ensure that the database connection is closed properly using a finally block.

**Know When To Draw The Line**
There are lots of scenarios that will necessitate the use of the Try and Except block, However, you must be careful; while try and except blocks are valuable for error handling, it's essential to use them judiciously and at the appropriate time. You must be able to strike a balance between handling exceptions gracefully and keeping your code clear and maintainable.

Excess use of the Try and Except block has its consequences. It can obscure your logic, reduce the performance of your application, make debugging more challenging, and make the entire codebase difficult to maintain.

Do not get carried away and start using exceptions for things that If statements can conveniently do. A great tip will be to use exceptions for conditions that are beyond you. for instance network errors, as the developer, you cannot control your user's network situations, If you are making an API call, The other application might be experiencing downtime, it's not your fault, there is no way you can control that, such conditions are perfect for the use of the Try and Except Block.

**How To Use The Try And Except Block**
There is no great lecture on how to use the Try and Except block in Python other than:

- Identifying the code that might Raise an exception or error
.

- Wrapping the code in question in a 'Try' Block


- Handling the exception/error within the 'Except' block


- Setting the 'Finally' Block to be executed regardless of whether an exception occurred. (This is mostly optional)

`

```
try:
    # Code that may raise an exception
except SpecificExceptionType as e:
    # Handle SpecificExceptionType
except AnotherExceptionType as e:
    # Handle AnotherExceptionType
finally:
#code to run whether an exception occurred or not
```
`
Here is a simple example

`

```
try:
    user_input = input("Enter a number: ")
    number = int(user_input)
    print(f"You entered the number: {number}")
except ValueError as e:
    print(f"Invalid input: {e}")
finally:
    print("Nothing to be done")
```
`
Sometimes one might anticipate more than one exceptionType to occur, you can just stack them all up, one after the other.

`

```
x= int(input("Insert a Numerator: "))
y = int(input("Insert a denominator: "))
try:
    result = x/y
    print(result)
except ValueError as e:
    print("error: {}".format(e))
except ZeroDivisionError as e:
    print("error: {}".format(e))
```
`
The above code snippet allows the user to input a numerator and a denominator. It then attempts to perform division and handles two specific types of exceptions: ValueError (for non-integer input) and ZeroDivisionError (for dividing by zero). If any of these exceptions occur, the code gracefully handles them by displaying an error message, preventing the program from crashing.

That is it!!! This wraps up my little rant about the Try and Except Block. Take-home lessons will be to use the TRY and EXCEPT blocks where they are genuinely needed; Avoid using exceptions for routine flow control and Keep the error-handling logic as close as possible to where the error occurs.

Thanks for coming to my TED Talk, If you enjoyed this, kindly leave a comment, and follow me on:

**Twitter: @codemistress1 
Linkedin: linkedin.com/in/chinemere-chukwu**