7b. Prof. Rosenthal’s Additions#

Additions to Chapter 7: Iteration and Search: topics that the chapter uses, but does not explain. Read this page after the chapter. The practice questions at the end have answers: try each question first, then open its Answer.

Run this page on Colab

Run the setup cell below first. In Colab, it downloads the file words.txt (the word list that Chapter 7 uses), and thinkpython.py, which lets this page show the errors of some examples without stopping the page.

from os.path import basename, exists

def download(url):
    filename = basename(url)
    if not exists(filename):
        from urllib.request import urlretrieve

        local, _ = urlretrieve(url, filename)
        print("Downloaded " + str(local))
    return filename

download('https://github.com/AllenDowney/ThinkPython/raw/v3/thinkpython.py');
download('https://raw.githubusercontent.com/AllenDowney/ThinkPython/v3/words.txt');

import thinkpython

Opening a file on your own computer#

Chapter 7 opens the word list with open('words.txt'). In Colab, this works because the chapter’s setup cell downloads words.txt first. If you run Python on your own computer (for example, in Jupyter, VS Code or Spyder), you must download the file yourself:

Click here to download words.txt

Most browsers save the file in your Downloads folder. If the browser shows the words instead of saving the file, right-click the link and choose Save Link As… (or Download Linked File).

After the download, open('words.txt') can still fail on your computer, with an error like this one:


file_object = open('a_file_that_is_not_here.txt')
FileNotFoundError: [Errno 2] No such file or directory: 'a_file_that_is_not_here.txt'

The reason: when you give open only a file name, Python looks for the file in one folder only, the working directory (see “Diving deeper: relative paths and the working directory” below). On your computer, the working directory is usually not your Downloads folder.

The sure way to open the file is to give open the full path of the file.

Full paths#

A full path (also called an absolute path) names the file and every folder that contains it, from the top folder of the disk down to the file. In Python, separate the folders with forward slashes (/).

  • On Windows, a full path starts with a drive letter and a colon: C:/Users/YOUR_NAME/Downloads/words.txt

  • On a Mac (and on Linux), a full path starts with a slash: /Users/YOUR_NAME/Downloads/words.txt

YOUR_NAME is your user name on the computer. To open the file, put its full path in a string and give the string to open. The sections below show how to find the full path of your Downloads folder.

Windows: the full path of the Downloads folder#

Find the path:

  1. Open File Explorer (press the Windows key and E together).

  2. In the list on the left, click Downloads.

  3. Click an empty part of the address bar at the top of the window (to the right of the folder names). The address bar now shows the full path of the folder, for example C:\Users\alice\Downloads.

Use the path in Python. Windows shows the path with backslashes (\). When you type the path in Python, type a forward slash (/) for each backslash, and add the file name at the end:

file_object = open('C:/Users/alice/Downloads/words.txt')

Replace alice with your own user name. Python on Windows accepts forward slashes, so this opens the file words.txt in your Downloads folder.

Mac: the full path of the Downloads folder#

Find the path:

  1. Open Finder, and click Downloads in the sidebar on the left.

  2. Hold down the Control key and click the file words.txt (or right-click it).

  3. While the menu is open, hold down the Option key. The menu item Copy “words.txt” changes to Copy “words.txt” as Pathname. Click it.

This copies the full path of the file, for example /Users/alice/Downloads/words.txt. The Downloads folder is always /Users/YOUR_NAME/Downloads. To see YOUR_NAME, open Terminal (in Applications > Utilities), type whoami and press Return.

Use the path in Python. A Mac path has forward slashes only, so you can paste it into a string as it is:

file_object = open('/Users/alice/Downloads/words.txt')

Replace alice with your own user name.

Reading the file with its full path#

When open has the full path, the rest of the code is the same as in Chapter 7. For example, this code counts the words in the file. Use the path for your computer:

total = 0
for line in open('C:/Users/alice/Downloads/words.txt'):     # Windows
# for line in open('/Users/alice/Downloads/words.txt'):     # Mac
    total += 1
print(total)

for loops and iterables#

Chapter 7 uses a for loop with a range, with a string and with a file. These are three examples of the same idea. A for loop works with any iterable: a value that can give its items one at a time. The general form of a for loop is:

for VARIABLE in ITERABLE:
    SOME_CODE

The loop assigns the first item of ITERABLE to VARIABLE and runs the body, then assigns the next item and runs the body again, until there are no more items. What an “item” is depends on the type of the iterable:

Iterable

Its items

Example

a range

integers

for i in range(1, 4):

a string

the characters of the string, one at a time

for letter in 'Gadsby':

a file object

the lines of the file, one at a time (as strings, each with a newline at the end)

for line in open('words.txt'):

A range is an iterable of integers:

for i in range(1, 4):
    print(i)
1
2
3

A string is an iterable of characters. Spaces and punctuation are characters too:

for letter in 'Hi, Bob':
    print(letter)
H
i
,
 
B
o
b

A file object is an iterable of lines. This loop counts the lines of words.txt, and displays the first 3 of them (without the newline at the end of each line):

count = 0
for line in open('words.txt'):
    count += 1
    if count <= 3:
        print(line.strip())
aa
aah
aahed

reversed makes an iterable that gives the items of another iterable in the opposite order. It works with strings and ranges:

for letter in reversed('stop'):
    print(letter, end=' ')
print()
for i in reversed(range(1, 4)):
    print(i, end=' ')
p o t s 
3 2 1 

Later chapters show more iterables. For example, a list (Chapter 9) is an iterable of the values in the list.

Not every value is an iterable. An integer or a float has no items, so a for loop over it causes a TypeError. To repeat something 5 times, loop over range(5), not over 5:


for i in 5:
    print(i)
TypeError: 'int' object is not iterable

A file object gives its lines only once. A file object remembers how far it has read. When a loop gets to the end of the file, the file object has no more lines, so a second loop over the same file object does not run its body. Here, the second loop counts nothing:

file_object = open('words.txt')

count = 0
for line in file_object:
    count += 1
print('first loop:', count)

count = 0
for line in file_object:
    count += 1
print('second loop:', count)
first loop: 113783
second loop: 0

To read the file again, call open again: it makes a new file object that starts at the beginning of the file. A range and a string do not have this problem: you can loop over them again and again.

Practice questions#

Question 1 (easy): what is displayed?#

Predict what this code displays. Then run the cell to check (on the website, click Show code cell output).

for ch in 'Yes!':
    print(ch, end='-')

Hide code cell output

Y-e-s-!-

Question 2 (easy): open a file on Windows#

On a Windows computer, the address bar of File Explorer shows that the file scores.txt is in the folder C:\Users\maria\Documents\class. Write the call to open that opens the file. Use forward slashes.

Question 3 (medium): what happens?#

Predict what happens when this code runs:

for digit in 2024:
    print(digit)

Question 4 (medium): relative paths#

The working directory is C:/Users/alice/Documents. Give the full path of the file that each call opens.

  • Part a: open('words.txt')

  • Part b: open('python/words.txt')

  • Part c: open('../Downloads/words.txt')

  • Part d: open('C:/Users/alice/Downloads/words.txt')

Question 5 (medium): write a function#

Write a function called count_lines that takes the path of a file (a string) and returns the number of lines in the file. For example, count_lines('words.txt') returns the number of words in the word list.

Start from this header (replace ... with the body):

def count_lines(path):
    ...

Question 6 (hard): what is displayed?#

Predict what this code displays. Then run the cell to check (on the website, click Show code cell output).

file_object = open('words.txt')
count = 0
for line in file_object:
    count += 1
for line in file_object:
    count += 1
print(count)

Hide code cell output

113783

Question 7 (hard): write a function#

Write a function called count_letter that takes a string text and a one-character string letter, and returns the number of times that letter is in text. Upper and lower case count as the same letter. For example, count_letter('Banana', 'a') returns 3, and count_letter('Banana', 'B') returns 1.

Start from this header (replace ... with the body):

def count_letter(text, letter):
    ...

Credits#

Additions by Prof. Y. Rosenthal, for Think Python: 3rd Edition by Allen B. Downey. Text license: Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International