CIS 2020 · Python for Everyone · Module 4 · Study guide

Module 4 review: input/output, character values, escape sequences, and lists

This module closes out Chapter 2 with two short special topics on how text is really stored, then opens Chapter 6: lists, the container that holds many related values under one name, and the handful of algorithms you will reuse on every list you ever write.

Section 2.5

Input and output

Getting a value in from the user, converting it to something you can compute with, and printing it back out in a shape a person can read.

Reading input and the prompt

The input function reads a line of text the user types and returns it. The program pauses at that statement until the user presses Enter. The prompt is the message displayed to say what to type, passed as input's argument; without one, the program looks frozen, since nothing tells the user anything is expected.

name = input("Enter your name: ")
print("Hello,", name)

input always returns a string, no matter what the user types. Digits typed at the prompt come back as a string of digits, not a number.

Numerical input

Because input returns a string, a value meant for arithmetic must be converted right where it is read: int(text) for a whole quantity, float(text) for one with a fractional part. If the user types something that is not a number, the conversion raises a ValueError at run time.

count = int(input("How many packs? "))
price = float(input("Price per pack: $"))
total = count * price
print("Total: $", total)

Formatted output

A format string mixes text with format specifiers: %d for an integer, %f for a float, %s for a string. In %10.2f, the 10 is the field width, the minimum character positions the value occupies (padded and right justified), and the .2 is the precision, the digits shown after the decimal point. Precision only changes the display; the stored value is untouched.

price = 4.5
print("Total: $%.2f" % price)

for p in (4.5, 129.0, 3.25):
    print("$%10.2f" % p)
# output:
#      $4.50
#    $129.00
#      $3.25

Special Topic 2.4 · p. 46

Character values

Underneath every letter on the screen is a plain number. This is that number.

A character is stored internally as an integer value: characters are not stored as shapes, but as numbers from a standard set of codes, and the letter you see on screen is only how that integer gets displayed. The textbook's Appendix D lists the values used for the characters common in Western European languages. Look up the character "H" there and you find it is encoded as the number 72.

ord takes a character and returns its numeric code; chr takes a numeric code and returns the character it stands for. They are inverses of each other.

print("The letter H has a code of", ord("H"))
print("Code 97 represents the character", chr(97))
# output:
# The letter H has a code of 72
# Code 97 represents the character a
print(ord("A"))      # 65
print(chr(65))       # A
print(chr(ord("A") + 1))   # B, the next letter

The codes Python works with are Unicode code points: the values ord() returns form an ordered sequence of integers running from 0 up to 0x10FFFF, over a million possible code points in all, of which 159,801 are currently assigned to an actual character. Because that sequence has a fixed order, it defines a total ordering on characters — every character has a code, and every code can be compared to every other. That is exactly why strings can be compared lexicographically: 'a' < 'b' is true because 97 < 98, and it is this same character-by-character numeric comparison that makes sorting and searching on strings behave the way you expect.

print('a' < 'b')          # True, because ord('a') is 97 and ord('b') is 98
print(ord('a') < ord('b'))   # True -- the comparison you're really making
print(sorted(["banana", "Apple", "cherry"]))
# ['Apple', 'banana', 'cherry'] -- capital letters have lower codes, so they sort first
ord and chr are inverses ord applied to the character A returns the number 65. chr applied to 65 returns the character A back. The two functions undo each other. "A" ord() 65 chr()
ord finds the code; chr finds the character. Applying one after the other returns you to where you started.

Working with the numeric code instead of the character itself is useful because numbers can be compared and calculated with. Codes for the letters run in alphabetical order, so comparing two codes puts characters in order, and adding to a code steps a letter forward.

letter = "m"
if letter < "s":
    print(letter, "comes before s")

next_letter = chr(ord(letter) + 1)   # "n"

Special Topic 2.5 · p. 47

Escape sequences

A way to put a character in a string literal that the string's own punctuation would otherwise swallow.

The escape character is the backslash. An escape sequence is the backslash together with the character right after it, read as a single unit standing for something other than what those two characters normally mean.

The four escape sequences from this section.
SequenceProduces
\"a quotation mark, as part of the string's contents
\\one literal backslash
\na newline — output moves to the start of the next line
\ta tab — output advances to the next tab stop
print("She said \"hello\" to me.")
print("C:\\Users\\student")
print("Line one\nLine two")
print("Name:\tGrade")
# output:
# She said "hello" to me.
# C:\Users\student
# Line one
# Line two
# Name:	Grade

The quotation mark normally marks where a string literal ends, so writing one plainly inside a string would end the string early and leave a syntax error. The backslash tells Python to treat that quotation mark as ordinary content instead.

The backslash itself never appears in the output. It is an instruction about how to read the next character, and it is consumed in the process — which is exactly why one literal backslash takes two characters, \\, to write in source code.

Section 6.1

Basic properties of lists

A single name that holds many values, each one findable by a position number.

A list is a container that holds a sequence of values under one name; each value it holds is an element. An index identifies one element by position, and indexes start at 0: the first element is at index 0, the last is at index len(list) - 1.

grades = [91, 84, 77, 95]
print(grades[0])      # 91, the first element
print(grades[3])      # 95, the last element
print(len(grades))    # 4
Positive indexes count from the front, negative indexes from the back A list of four elements: 91, 84, 77, 95. Positive indexes above the boxes read 0, 1, 2, 3. Negative indexes below the boxes read -4, -3, -2, -1, so index 3 and index -1 both refer to the same last element, 95. 91 84 77 95 0 1 2 3 -4 -3 -2 -1 grades[3] and grades[-1] are the same element

A list is mutable: its contents can change after it is created. A string cannot be changed this way; any operation that looks like it edits a string actually builds a new one.

grades[0] = 100        # replaces the element in place, no new list created

Using an index that does not exist, equal to or past the length, raises an IndexError: an index out of range error. It is caught only while the program runs, at the line that uses the bad index, so it is a run-time error, not a syntax error.

grades[10]   # IndexError: list index out of range

Section 6.2

List operations

Adding, removing, searching — and the one behavior of lists that causes more debugging sessions than anything else in this course.

Adding and removing elements.
OperationIdentifies the element byEffect
list.append(x)—adds x at the end
list.insert(i, x)position iadds x at position i, later elements shift right
list.remove(x)value xdeletes the first element equal to x, later elements shift left
list.pop(i)position i (default: last)deletes and returns the element at that position
names = ["Ann", "Ben", "Cal"]
names.append("Dee")        # ["Ann", "Ben", "Cal", "Dee"]
names.insert(1, "Amy")     # ["Ann", "Amy", "Ben", "Cal", "Dee"]
names.remove("Cal")        # ["Ann", "Amy", "Ben", "Dee"]
last = names.pop()         # last = "Dee", names is now ["Ann", "Amy", "Ben"]

remove is given a value and must search for it, deleting only the first match; pop is given a position and hands back the element it removed.

Searching a list

The in operator reports whether a value occurs anywhere in the list, true or false. The index method reports the position of the first match, and raises a ValueError if the value is not present. Checking with in first avoids that crash.

if "Ben" in names:
    print(names.index("Ben"))   # 2
else:
    print("not found")

Aliases and copies

Assigning one list variable to another does not copy its contents; it copies a reference, so both names lead to the exact same list. A second name for the same list is an alias.

a = [1, 2, 3]
b = a              # b is an alias for a, not a copy
b.append(4)
print(a)           # [1, 2, 3, 4]  -- a changed too!

c = a.copy()       # or list(a), or a[:] -- a real, independent copy
c.append(99)
print(a)           # [1, 2, 3, 4]  -- unaffected this time
An alias is a second name for the same list Both a and b point to one single list box holding 1, 2, 3, 4. A third name, c, points to a separate, independent list box holding 1, 2, 3, 99. a b [1, 2, 3, 4] one list, two names c [1, 2, 3, 99] a real, separate copy
Changing the list through b changes it for a too, since they are the same list. c was copied, so it does not share changes with a.

This only matters because lists are mutable. Aliasing a string variable is harmless — no operation can change a string in place, so there is nothing for a second name to accidentally affect.

Section 6.3

Common list algorithms

Four patterns that cover almost everything you will ever do with a single list. Learn the shape, not just the code.

Sum

Start a running total at zero, visit every element, and add each one in.

total = 0
for g in grades:
    total = total + g

Largest (or smallest)

Start by assuming the first element is the largest, then check the rest, replacing the remembered value whenever something bigger turns up.

largest = grades[0]
for g in grades[1:]:
    if g > largest:
        largest = g

Starting from an actual element matters: if the list holds only negative numbers, starting from 0 would report 0 as the maximum even though it never appears in the list.

Linear search

Visit elements one at a time, compare each to the target, and stop the moment a match is found. Unlike sum or count, a search can end early.

target = 77
found = False
for g in grades:
    if g == target:
        found = True
        break

Counting matches

Start a counter at zero, visit every element, and add one whenever an element passes a test. This one always visits the whole list, since an early match does not rule out later ones.

passing = 0
for g in grades:
    if g >= 70:
        passing = passing + 1
The four patterns, side by side.
AlgorithmStarts fromVisits every element?
Sum0Yes, always
Largest / smallestthe first elementYes, always
Linear search—No, stops at the first match
Counting matches0Yes, always

Quick check

If you remember only these

  • input always returns a string; convert with int() or float() right where you read it.
  • In %10.2f, 10 is the field width and 2 is the precision. Precision changes only the display, never the stored value.
  • ord turns a character into its numeric code; chr turns a code back into a character. They undo each other.
  • An escape sequence is a backslash plus the next character, read as one unit: \", \\, \n, \t. The backslash itself never appears in the output.
  • Indexes start at 0. list[-1] is the last element. Using an index that does not exist raises IndexError at run time.
  • Lists are mutable, strings are not. remove(value) searches for a value; pop(index) takes a position and returns what it removed.
  • Assigning a list to another variable makes an alias, not a copy — both names share one list. Use .copy(), list(x), or x[:] for an independent copy.
  • Sum, largest, and counting matches all visit the entire list. Linear search is the one that can stop early.