Review Simple Functions Exception Handling

PythonPythonBeginner
Practice Now

This tutorial is from open-source community. Access the source code

Introduction

In this lab, you will learn how to review the definition of simple functions in Python and explore exception handling. Functions are a key programming concept that enables you to structure code into reusable segments. Exception handling, on the other hand, is a method for dealing with errors and unforeseen circumstances in your programs.

The main objectives of this lab are to review the process of defining simple functions and to learn about exception handling in Python. The file that will be modified is pcost.py.

This is a Guided Lab, which provides step-by-step instructions to help you learn and practice. Follow the instructions carefully to complete each step and gain hands-on experience. Historical data shows that this is a beginner level lab with a 90% completion rate. It has received a 97% positive review rate from learners.

Defining a Function

In this step, we're going to learn how to create a function. A function in Python is a block of organized, reusable code that is used to perform a single, related action. Here, our function will read portfolio data from a file and calculate the total cost. This is useful because once we have this function, we can use it multiple times with different portfolio files, saving us from writing the same code over and over again.

Understanding the Problem

In the previous lab, you might have written some code to read portfolio data and calculate the total cost. But that code was probably written in a way that can't be easily reused. Now, we're going to convert that code into a reusable function.

The portfolio data files have a specific format. They contain information in the form of "Symbol Shares Price". Each line in the file represents a stock holding. For example, in a file named portfolio.dat, you might see lines like this:

AA 100 32.20
IBM 50 91.10
...

Here, the first part (like "AA" or "IBM") is the stock symbol, which is a unique identifier for the stock. The second part is the number of shares you own of that stock, and the third part is the price per share.

Creating the Function

Let's create a Python file called pcost.py in the /home/labex/project directory. This file will contain our function. Here's the code that we'll put in the pcost.py file:

def portfolio_cost(filename):
    """
    Computes the total cost (shares*price) of a portfolio file

    Args:
        filename: The name of the portfolio file

    Returns:
        The total cost of the portfolio as a float
    """
    total_cost = 0.0

    ## Open the file and read through each line
    with open(filename, 'r') as f:
        for line in f:
            fields = line.split()
            ## Extract the data (symbol, shares, price)
            shares = int(fields[1])
            price = float(fields[2])
            ## Add the cost to our running total
            total_cost += shares * price

    return total_cost

## Call the function with the portfolio.dat file
if __name__ == '__main__':
    cost = portfolio_cost('/home/labex/project/portfolio.dat')
    print(cost)

In this code, we first define a function named portfolio_cost that takes a filename as an argument. Inside the function, we initialize a variable total_cost to 0.0. Then we open the file using the open function in read mode ('r'). We use a for loop to go through each line in the file. For each line, we split it into fields using the split() method. We then extract the number of shares and convert it to an integer, and the price and convert it to a float. We calculate the cost for that stock holding by multiplying the number of shares by the price and add it to the total_cost. Finally, we return the total_cost.

The part if __name__ == '__main__': is used to call the function when the script is run directly. We pass the path to the portfolio.dat file to the function and print the result.

Testing the Function

Now, let's run the program to see if it works. We need to navigate to the directory where the pcost.py file is located and then run the Python script. Here are the commands to do that:

cd /home/labex/project
python3 pcost.py

After running these commands, you should see the output:

44671.15

This output represents the total cost of all the stocks in the portfolio.

Understanding the Code

Let's break down what our function does step by step:

  1. It takes a filename as an input parameter. This allows us to use the function with different portfolio files.
  2. It opens the file and reads it line by line. This is done using the open function and a for loop.
  3. For each line, it splits the line into fields using the split() method. This method splits the line into a list of strings based on whitespace.
  4. It converts the number of shares to an integer and the price to a float. This is necessary because the data read from the file is in string format, and we need to perform arithmetic operations on them.
  5. It calculates the cost (shares * price) for each stock holding and adds it to the running total. This gives us the total cost of the portfolio.
  6. It returns the final total cost. This allows us to use the result in other parts of our program if needed.

This function is now reusable. We can call it with different portfolio files to calculate their costs, which makes our code more efficient and easier to maintain.

✨ Check Solution and Practice

Adding Error Handling

When you're working with real - world data, it's very common to come across inconsistencies or errors. For example, the data might have missing values, incorrect formats, or other issues. Python offers exception handling mechanisms to deal with these situations gracefully. Exception handling allows your program to continue running even when it encounters an error, instead of crashing abruptly.

Understanding the Problem

Let's take a look at the portfolio3.dat file. This file contains some data about a portfolio, like the stock symbol, the number of shares, and the price per share. To view the contents of this file, we can use the following command:

cat /home/labex/project/portfolio3.dat

When you run this command, you'll notice that some lines in the file have dashes (-) instead of numbers for the shares. Here's an example of what you might see:

AA 100 32.20
IBM 50 91.10
C - 53.08
...

If we try to run our current code on this file, it will crash. The reason is that our code expects to convert the number of shares into an integer, but it can't convert a dash (-) into an integer. Let's try running the code and see what happens:

python3 -c "import sys; sys.path.append('/home/labex/project'); from pcost import portfolio_cost; print(portfolio_cost('/home/labex/project/portfolio3.dat'))"

You'll see an error message like this:

ValueError: invalid literal for int() with base 10: '-'

This error occurs because Python can't convert the - character to an integer when it tries to execute int(fields[1]).

Introduction to Exception Handling

Python's exception handling uses try and except blocks. The try block contains the code that might raise an exception. An exception is an error that occurs during the execution of a program. The except block contains the code that will be executed if an exception occurs in the try block.

Here's an example of how try and except blocks work:

try:
    ## Code that might raise an exception
    result = risky_operation()
except ExceptionType as e:
    ## Code to handle the exception
    print(f"An error occurred: {e}")

When Python executes the code in the try block, if an exception occurs, the execution immediately jumps to the matching except block. The ExceptionType in the except block specifies the type of exception that we want to handle. The variable e contains information about the exception, such as the error message.

Modifying the Function with Exception Handling

Let's update our pcost.py file to handle errors in the data. We'll use the try and except blocks to skip the lines with bad data and show a warning message.

def portfolio_cost(filename):
    """
    Computes the total cost (shares*price) of a portfolio file
    Handles lines with bad data by skipping them and showing a warning.

    Args:
        filename: The name of the portfolio file

    Returns:
        The total cost of the portfolio as a float
    """
    total_cost = 0.0

    ## Open the file and read through each line
    with open(filename, 'r') as f:
        for line in f:
            fields = line.split()
            try:
                ## Extract the data (symbol, shares, price)
                shares = int(fields[1])
                price = float(fields[2])
                ## Add the cost to our running total
                total_cost += shares * price
            except ValueError as e:
                ## Print a warning for lines that can't be parsed
                print(f"Couldn't parse: '{line}'")
                print(f"Reason: {e}")

    return total_cost

## Call the function with the portfolio3.dat file
if __name__ == '__main__':
    cost = portfolio_cost('/home/labex/project/portfolio3.dat')
    print(cost)

In this updated code, we first open the file and read it line by line. For each line, we split it into fields. Then, we try to convert the number of shares to an integer and the price to a float. If this conversion fails (i.e., a ValueError occurs), we print a warning message and skip that line. Otherwise, we calculate the cost of the shares and add it to the total cost.

Testing the Updated Function

Now let's run the updated program with the problematic file. First, we need to navigate to the project directory, and then we can run the Python script.

cd /home/labex/project
python3 pcost.py

You should see output like this:

Couldn't parse: 'C - 53.08
'
Reason: invalid literal for int() with base 10: '-'
Couldn't parse: 'DIS - 34.20
'
Reason: invalid literal for int() with base 10: '-'
44671.15

The program now does the following:

  1. It attempts to process each line of the file.
  2. If a line contains invalid data, it catches the ValueError.
  3. It prints a helpful message about the problem.
  4. It continues processing the rest of the file.
  5. It returns the total cost based on the valid lines.

This approach makes our program much more robust when dealing with imperfect data. It can handle errors gracefully and still provide useful results.

✨ Check Solution and Practice

Interactive Experimentation

Python offers an interactive mode that lets you run code right away. This is super useful for testing out your code and trying new things. In this step, we'll learn how to call a function directly from the Python interpreter.

Running Python in Interactive Mode

To run a Python script and then enter the interactive mode, you can use the -i flag. This flag tells Python to keep running in an interactive state after executing the script. Here's how you do it:

cd /home/labex/project
python3 -i pcost.py

Let's break down what this command does:

  1. First, cd /home/labex/project changes the current directory to /home/labex/project. This is where our pcost.py script is located.
  2. Then, python3 -i pcost.py executes the pcost.py script. After the script finishes running, Python stays in interactive mode.
  3. In interactive mode, you can type Python commands directly into the terminal.

After running the command, you'll see the output of the pcost.py script, followed by the Python prompt (>>>). This prompt indicates that you can now enter Python commands.

Calling Your Function Interactively

Once you're in the interactive mode, you can call the portfolio_cost() function with different filenames. This allows you to see how the function behaves with various inputs. Here's an example:

>>> portfolio_cost('/home/labex/project/portfolio.dat')
44671.15
>>> portfolio_cost('/home/labex/project/portfolio2.dat')
19908.75
>>> portfolio_cost('/home/labex/project/portfolio3.dat')
Couldn't parse: 'C - 53.08
'
Reason: invalid literal for int() with base 10: '-'
Couldn't parse: 'DIS - 34.20
'
Reason: invalid literal for int() with base 10: '-'
44671.15

Using this interactive approach, you can:

  • Test your function with different inputs to see if it works as expected.
  • Experiment with the function's behavior under various conditions.
  • Debug your code on the fly by seeing the immediate results of your function calls.

Benefits of Interactive Mode

Interactive mode has several benefits:

  1. You can quickly test different scenarios without having to run the entire script every time.
  2. You can inspect variables and expression results immediately, which helps you understand what's going on in your code.
  3. You can test small pieces of code without creating a full program. This is great for learning and trying out new ideas.
  4. It's an excellent way to learn and experiment with Python because you get instant feedback.

Exiting Interactive Mode

When you're done experimenting, you can exit the interactive mode in two ways:

  • Type exit() and press Enter. This is a straightforward way to end the interactive session.
  • Press Ctrl+D (on Unix/Linux). This is a shortcut that also exits the interactive mode.

Throughout your Python programming journey, the technique of defining functions and testing them interactively will be extremely valuable for development and debugging. It allows you to quickly iterate on your code and find and fix issues.

✨ Check Solution and Practice

Summary

In this lab, you have learned several key Python programming concepts. First, you learned how to define and use functions, which makes your code reusable. Second, you mastered implementing exception handling, enhancing the robustness of your programs. Lastly, you discovered how to use Python in interactive mode for testing and experimentation.

These skills are fundamental for writing reliable Python programs. Functions help organize and reuse code, exception handling enables graceful handling of unexpected situations, and interactive mode offers a powerful environment for testing and debugging. As you progress in your Python learning, these concepts will prove increasingly valuable for developing larger and more complex applications.