Programming Techniques#

Objectives#

  • To use control structures to clean and transform data in an automated way

  • To write basic functions to reduce redundancy

  • To interpret Python exceptions (error messages) in order to fix bugs

Introduction#

The Python language offers many other tools and techniques to make code more robust, reusable, and efficient. One way to think about these tools and techniques is that they help us write programs as opposed to writing code, a program being some code that is designed for use by different users in different contexts. Even if you are the only user of your code, applying these programming techniques can make your work more productive and your code more effective.

This notebook is intended for you to work through independently, in order to review and clarify the concepts introduced on Python Camp Day 2, and to lay the groundwork for the activities on Python Camp Day 3. However, feel free to collaborate with others in working through it. It is also intended to serve as a resource you can return to review as necessary.

How to Use this Notebook

  1. Read the documentation above each cell containing code and run the cell (Ctrl+Enter or Cmd+Return) to view the output.

  2. Follow the prompts labeled Try it out! that ask you to write your own code in the provided blank cells.

  3. (Hidden) solutions to these exercises follow the blank cells; click the toggle bar to expand the solution to compare with your approach.

  4. Some prompts include alternative exercises (Parsons Problems) that will be linked from the prompt. These alternatives may help clarify concepts (especially if you find yourself struggling to keep up with all the syntax).

  5. Optional annotations (labeled For the curious...) provide additional explanation and/or context for those who want them. Feel free to skip these sections if you like. As a beginner, it’s important to maintain a balanced cognitive load: taking in too much information all at once can impede your progress toward understanding. This balance looks different for everyone, but we have tried to keep the main content focused on a few key concepts, tools, and techniques, while providing that additional context for those who might benefit from it.

I. Loops & lists#

I.1 Doing things with strings & lists#

The real power of lists enters when we can use them to automate repetitive tasks.

In “Modeling Code” and “Describing the Team” we used what’s called a for loop to adjust items in a list. Here we’ll work up to the same sort of task, step by step, but we’ll add a couple of enhancements.

For this example, we’ll start with a list of strings representing book prices.

book_prices = ['$55.99', '$119.95', '$13.95', '$250.67', '$99.99']

First, let’s just print each price from the list on its own line.

for price in book_prices:
    print(price)

Notes

  1. Our loop begins with the Python keyword for. This is not a function – like len() or print() – but part of the Python syntax itself (like the quotation marks around strings or the square brackets around lists).

  2. for always goes with in; they make a pair.

  3. The variable price, immediately following for, is being created here. (It was not previously defined in our code.) Its role is to hold – in sequence – each item in the collection following in.

  4. book_prices was defined before the loop. The variable following in should always be some sort of collection type – a string, a list, a dictionary, etc. – or else a function that returns a collection. We cannot write for x in 10, for instance, because the integer 10 is not a collection; it holds no items within itself. (For the same reason, we can’t take a slice of 10.)

  5. The first line of the for loop ends in a colon, and the line or lines underneath it are indented (separated from the left margin by the same number of tabs or spaces). We call these indented lines in Python a block.

Animation

To help you visualize what’s happening inside for loop, here’s an animation of looping over a list of float values.

As this animation demonstrates, the loop variable, price, holds the last value in the list once the loop has finished.

Try it out!

All of the prices follow the same format, beginning with the dollar sign. To calculate the sales tax, we need to multiply each price by a fixed percentage – let’s say 110%, or 1.1, to reflect a sales tax of 10% on the dollar.

But as we saw above, we can’t perform math with strings, and book_prices is a list of strings. To convert our strings to numbers, we first need to remove the dollar sign from each price.

Modify the for loop above so that it prints each price without the dollar sign. For a hint, consult the example from yesterday’s homework where we created the variable course_section.

# Your code here

Now check your answer by expanding the hidden solution cell below.

Hide code cell content
for price in book_prices:
    print(price[1:])

Try it out!

Now that we have extracted the numeric part of the string (the part after the dollar sign), we can convert this string to a float in order to do math with it.

Modify the for loop again to do the following:

  1. Assign the slice of the price (without the dollar sign) to a new variable called price_num.

  2. Use the float() function to convert price_num to a float, and multiply the result by 1.1.

    For instance, to convert the string "1.5" (notice the quotations marks!) to its float representation, we would write float("1.5").

  3. Assign the result of this calculation to price_num and print it.

If the foregoing feels intimidating, try this Parsons Problem first. It allows you to focus on the logical order of the actions to be performed, rather than on the syntax of the commands.

# Your code here

Now check your answer by expanding the hidden solution cell below.

Hide code cell content
for price in book_prices:
    price_num = price[1:]
    price_num = float(price_num) * 1.1
    print(price_num)

II.2 From one list to another#

If you didn’t get the intended answer, don’t worry! You’ll get the hang of it. The most important thing for now is to understand that we used a for loop because we wanted to repeat a certain set of actions for all the items in a list.

For now, let’s add one enhancement to our loop: instead of just printing the new price (with the added sales tax), we’ll store it in a separate list.

To do this, we need to use a method of Python lists called append(). This method adds a new item to the end of a list.

Much like the split() method we used on strings, the append() method can be called from any Python list by writing the name of the list plus .append(item), where item is the value we want to add to the list.

See the code below and the explanation that follows.

prices_with_tax = []
for price in book_prices:
    price_num = price[1:]
    price_num = float(price_num) * 1.1
    prices_with_tax.append(price_num)
print(prices_with_tax)

Notes

This loop achieves the same thing as the previous, with this difference: the adjusted prices are now stored in the prices_with_tax variable, which is another list. This is a fairly common Python pattern; when using this pattern, here are a few rules of thumb to keep in mind:

  1. We need to create the new list outside of the loop. The line prices_with_tax = [] creates a new variable that consists of an empty list.

  2. As before, we use the loop variable price to work with each item in the book_prices list.

  3. The variable price_num is temporary, in the sense that, like the price loop variable, it will change (be reassigned to a new value) with every iteration of the loop.

  4. The line prices_with_tax.append(price_num) stores the value in price_num to our list. Without this step, we could not “save” the results of our calculations. It’s like performing a series of steps on a calculator: if you don’t write down your answer before moving onto the next problem, you will lose all your hard work!

  5. Steps 2, 3, and 4 are all indented underneath the line that kicks off the for loop. Visually, this tells you that all of these steps happen on each iteration of the loop (once for every item in the book_prices lists.

  6. The line print(prices_with_tax) is not indented, meaning that it will be executed after the for loop completes. That’s because we only want to print our new list when it’s finished, not every time we add a new item to it.

  7. Note that our book_prices list still holds the original strings: our code made a new, second list.

print(book_prices)

Try it out!

We have a list of strings that represent courses, where each string (as in the example above) consists of a department code, a course number, and a section number:

courses = ['CHEM 1001 10', 'CHEM 1001 11' ...]

Using a for loop, transform this list into three separate lists:

  • one to hold the department codes,

  • one to hold the course numbers,

  • and one to hold the section numbers.

The cells below will get you started. For more help, check out this Parsons Problem.

courses = ['CHEM 1001 10', 'CHEM 1001 11', 'BISC 1111 10', 'BISC 2207 10', 'PSC 1001 10',
           'PSC 1001 11', 'PSC 1001 12', 'ANTH 3808 10', 'AMST 2071 80']
depts = []
course_nums = []
sections = []
# Your code here

Now check your answer by expanding the hidden solution cell below.

Hide code cell content
for course in courses:
    course_info = course.split()
    depts.append(course_info[0])
    course_nums.append(course_info[1])
    sections.append(course_info[2])
print(depts)
print(course_nums)
print(sections)

II. Writing Functions#

We’ve met a number of functions and methods so far on our journey through the Python language. See how many you can name before expanding the cell below.

Functions and methods may feel pretty inscrutable. Unlike lists and dictionaries, we can’t “look inside” them to see what they consist of, the way we examined bkst_data to determine its structure. (We can read the source code for functions and methods, but unless you know what you’re looking for, that’s not always helpful.)

But in what follows, we’ll demystify functions a bit by writing our own.

A function (or a method) is just a way of encapsulating code. It’s like a shortcut on your computer (e.g., like hitting Ctrl+S or Cmd+S in order to save the current document, etc.). Functions make it easier to do the same thing multiple times without having to repeat yourself.

They can also help make your code more legible and easier to reason about.

II.1 Defining vs. calling functions#

Below is a simple Python function that prints a message to the screen.

def print_message():
    print("Hello from my function!")

Notes

When you run the above cell, you shouldn’t see any output. That’s because defining a function and using the function are two separate operations.

Let’s unpack our function definition, piece by piece:

  • The def keyword tells Python that we’re defining a function.

  • We have to give our function a name, following the same rules as for Python variable names (only letters, numbers, and underscores; must begin with a letter).

  • As with variables, our function names should be unique. We don’t want to give a function the same name as an existing Python function. For instance, calling this function print would overwrite the built-in Python print() function, which would mean that we could no longer use the latter.

  • Immediately after the function name, we need parentheses. Here the parentheses are empty because this function takes no arguments. We’ll look at arguments later.

  • Then there’s a colon (:), followed by an indented block (as in the for loops you wrote today).

  • The code in the indented block is the body of the function. The function body is what will be executed when we call the function

print_message()

In the cell above, we called the print_message() function. Calling a function, like defining a function, requires the parentheses, even when there are no arguments. The presence of the parentheses lets Python know that it should execute the code within the body of the function.

II.2 Arguments and return values#

We write functions and methods in order to be able to re-use code in different contexts. Basically, it saves us from having to repeat ourselves.

But our print_message() always prints the same message, which is not likely to be very useful.

Most functions are used to transform data in some way. Such functions take some input and return some (different) output. Examples you’ve seen so far include the following:

function name

input

output

len

a string or a list

an integer

open()

the name of a file as a string

a file handle (for working with the file’s contents)

float()

a string

a float

print()

one or more values of any Python type

those values, displayed on the screen

The arguments in the function definition are variables that hold the input. These variables are used within the body of the function (in the block of code that comes after the def line).

In order to produce output, a function will usually return a value, using the return keyword. return will usually start the last line of the function.

For instance, the function below calculates sales tax on a given price.

def add_sales_tax(price):
    # Price should be a numeric value
    # Returns the price + 10% for sales tax
    price_with_tax = price * 1.1
    return price_with_tax

Now we can use the add_sales_tax function with any price (provided we give it a float or integer for the price argument).

prices = [9.99, 11.99, 55.95, 100.19]
for p in prices:
    print('Price is', p)
    price_with_tax = add_sales_tax(p)
    print('Price with tax is', price_with_tax)

Notes

  • In the code above, we called add_sales_tax inside a for loop, passing it the loop variable p in parentheses.

  • During the execution of the function, the value of p is copied into to the price variable (which is internal to the function).

  • We are calling add_sales_tax() inside our loop, and assigning the result to the price_with_tax variable. Like the loop variable p, price_with_tax receives a new value on each iteration of the loop.

Try it out!

Write a function, dollars_to_float(), to convert a string starting with a dollar sign to a float. You’ve used this code before – now encapsulate it in a function so that you can re-use it in the future without retyping it.

Don’t forget to return something, otherwise your function will have no effect!

Once you’ve written your function, test it by calling it on the following strings:

  • '$10'

  • '$9.99'

  • '$200.00'

# Your code here
Hide code cell content
def dollars_to_float(dollar_amt):
    # Converts a string prefixed with a dollar sign to a float
    amt = dollar_amt[1:]
    return float(amt)

If you wrote the function as shown above (in the collapsed cell), you should be able to get the intended result for all three examples.

But an amount containing a comma should produce a ValueError:

dollars_to_float('$10,000.00')

III. Errors & Exceptions#

Errors can be jarring. For many of us, error messages on the computer inspire frustration, even anger. They may even make us feel misunderstood, or else that we lack understanding, that we just don’t “get” it.

Learning to program (in virtually any language) involves learning how to deal with errors. There’s no such thing as a piece of software without “bugs,” if only because for any given piece of software, someone can find a way to use it for which it was not intended.

In the example above, we didn’t design the function specifically to work for strings with commas, and indeed, it doesn’t. The ValueError – technically, this kind of error is called an exception – means simply that the Python interpreter encountered a kind of value it didn’t expect and doesn’t know what to do with.

Such errors/exceptions are valuable (no pun intended) to the programmer; they tell us where the bugs are (or might be) in our programs. Python even provides mechanisms for checking for errors proactively, so that our code doesn’t grind to a halt whenever it encounters one.

On Days 3 and 4, we’ll work more with errors and exceptions, and we’ll learn about an approach to writing code that uses errors to guide development.

Wrap up#

With for loops, we can automate actions that would otherwise be tedious, like calculating the sales tax of a (long) list of prices. And that’s one of the main reasons for learning to program: as the title of one popular book on Python puts it, “to automate the boring stuff”.

You wrote your first Python function, dollars_to_float. You also encountered some Python error messages, which we’ll learn more about on Day 3.

You’ll use your dollars_to_float function, as well as the skills covered in this homework, in the team exercises ahead.

By now, you have written Python code to solve various problems. Some problems could be solved in one or two lines; others (like finding the most expensive textbook in our dataset) required several lines of code.

Given all that you have learned so far, you could go on to solve many, many more problems using Python. In other words, we’ve covered the bare essentials; it’s one of the main advantages of Python (as a programming language) that these essentials can be covered in just a couple of days.