Lists, Strings and Files in Python
One dimensional and two dimensional lists, every string operation Paper 2 expects, and reading and writing text files, with the off by one traps that break more programs than anything else.
Lists
A list holds many values under one name, each found by its index, counted from 0.
scores = [14, 9, 21, 6, 18]
print(scores[0])
print(scores[-1])
scores[3] = 11
print(len(scores))scores[0] is 14 and scores[-1] is the last item. len(scores) is 5, and the last index is 4.
A five item list has len 5 and a highest index of 4. Looping to len(scores) runs one step too far and raises an IndexError.
Working through a list
total = 0
for score in scores:
total = total + score
print("Average:", total / len(scores))Loop over the items when you only need the values. Loop over range(len(scores)) when you need the index as well, for example to change items in place.
Useful list operations
scores.append(25)
scores.insert(0, 3)
scores.remove(9)
value = scores.pop()
scores.sort()
print(max(scores), min(scores), sum(scores))Two dimensional lists
A list of lists, useful for anything grid shaped.
board = [[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]
print(board[1][2])
for row in board:
for cell in row:
print(cell, end=" ")
print()The first index selects the row, the second the position within it.
- The list holds its items in order, and the first locker is number 0.
- append() puts a new item on the end, so the list grows.
- Assign to an index to replace what is there. The old value is gone.
- scores[2] opens locker 2. len(scores) counts the lockers, so the last index is one less.
Strings
A string is a sequence of characters, indexed from 0 just like a list.
word = "Computing"
print(len(word))
print(word[0])
print(word[0:3])
print(word[-1])
print(word.upper())
print(word.lower())
print(word.find("put"))
print(word.replace("ing", "er"))
print("put" in word)word[0:3] is a slice, and it gives characters 0, 1 and 2. Like range, a slice stops before the second number.
Splitting and joining
line = "Amira,15,Year 10"
parts = line.split(",")
print(parts[0])
joined = "-".join(parts)split is how you take a line read from a file apart, and it is needed in almost every Paper 2 task that involves a data file.
Characters as numbers
print(ord("A"))
print(chr(66))ord gives the character set code and chr converts back, which is how case conversion and simple ciphers are done.
- Every character has an index. The first is 0, and negative indexes count back from the end.
- A slice [a:b] runs from index a up to, but not including, b. Leave b out to go to the end.
- [-1] is the last character.
- Functions and methods build and search strings, and each one gives back a new string.
- upper() makes every letter a capital.
- strip() removes spaces from both ends.
- replace() swaps every match for something else.
- split() breaks a string into a list.
- join() builds a string from a list.
- find() gives the position of the first match, or -1 if there is none.
- A method returns a new string. The original is never changed unless you assign the result.
Files
A program that forgets everything when it closes is of limited use. Writing to a file makes data persist between runs.
Reading
file = open("scores.txt", "r")
for line in file:
print(line.strip())
file.close()strip() removes the newline character at the end of each line, and forgetting it is why comparisons against read values so often fail.
The safer form closes the file for you even if something goes wrong:
with open("scores.txt", "r") as file:
lines = file.readlines()Writing
with open("scores.txt", "w") as file:
file.write("Amira,18\n")
file.write("Ben,14\n")Opening in write mode empties the file before you write anything. Use "a" to append to the end and keep what is already there. Losing a data file this way in a Paper 2 task costs a great deal of time.
Putting it together
totals = {}
with open("scores.txt", "r") as file:
for line in file:
parts = line.strip().split(",")
name = parts[0]
score = int(parts[1])
totals[name] = score
for name in totals:
print(name, totals[name])Note the int() on the score. Everything read from a text file is a string, every time.
- r reads. The file is only looked at, and it must already exist.
- w writes. Everything already in the file is erased first.
- a appends. New lines go on the end and the old ones are kept.
- with closes the file for you, and \n ends a line.
Key terms you must be able to define
- List
- A Python data structure holding many values under one name, accessed by index.
- Index
- The position of an item, counted from zero.
- Two dimensional list
- A list whose items are themselves lists, used for grids and tables.
- Slice
- A section of a list or string taken between two indexes, stopping before the second.
- split
- A string method that divides a string into a list at a given separator.
- strip
- A string method that removes whitespace, including the newline, from both ends.
- append
- A list method that adds an item to the end.
- Append mode
- Opening a file with "a" so that new data is added to the end rather than replacing it.
Flashcards
Say the definition out loud before you flip the card. Retrieving it from memory is what builds recall, reading it again is not.
Reach the top grade on this topic
Paper 2 tasks are almost always list or file tasks, so the details here are worth more than anywhere else.
Strip and cast every line you read. int(line.strip()) handles both the newline and the type in one step, and skipping either produces a fault that is hard to see because the value looks correct when printed.
Use len(list) - 1 when you need the last index. Write it deliberately rather than by habit, and check it against a small example.
Choose the loop that matches what you need. for item in list when you only need values, for i in range(len(list)) when you need to change items in place.
Open files in the right mode. Reading is "r", appending is "a", and "w" empties the file first. Say why you chose the mode if a question asks.
Mistakes that cost marks here
- Looping to len(list) rather than len(list) - 1 when using range with an index.
- Forgetting strip(), so a value read from a file carries a newline and never matches.
- Forgetting to cast a value read from a file before doing arithmetic with it.
- Opening a file in "w" mode when you meant to add to it, which deletes the existing contents.
- Expecting a slice like word[0:3] to include index 3. It stops before it.
Python counts from zero because an index is really an offset from the start of the data. The first item sits zero places along, which is also why a slice like [0:3] gives three items and stops before index 3.
Knowledge check
Exam-style questions
Five written questions in the style of the real paper. Write a full answer, then let the marker check it against the mark scheme.
- LSets an initial highest value from the list, such as marks[0]
- LLoops through the list
- LCompares each item with the current highest
- LUpdates the highest and outputs it after the loop
A correct program is: highest = marks[0], then for mark in marks: if mark > highest: highest = mark, then print("The highest mark is", highest). Starting from marks[0] rather than from zero matters, because a list containing only negative values would otherwise report zero as the highest. The print statement must be outside the loop, otherwise it outputs a running maximum on every pass rather than the final answer. Python's built in max(marks) would also be accepted.
- LA line read from a file includes the newline character at the end
- LThe typed name does not include that character, so the two strings differ
- LUsing strip() removes it so the comparison works
When a line is read from a text file it includes the newline character that ended the line in the file. The name typed by the user does not include that character, so although the two look identical when printed, one is a character longer than the other and the comparison is False. The fix is to remove the whitespace at the ends of the line read from the file, using name = line.strip(), after which the two strings genuinely are equal and the comparison succeeds. The same problem causes numbers read from files to fail if they are compared before being cast.
- LOpens the file for reading
- LLoops through each line of the file
- LSplits each line on the comma
- LCasts the score to an integer
- LCompares with 50 and outputs the name for those above it
A correct program is: with open("results.txt", "r") as file: then for line in file: then parts = line.strip().split(",") then name = parts[0] then score = int(parts[1]) then if score > 50: print(name). Three details carry the marks. The line must be stripped before splitting, or the score picks up a trailing newline. The score must be cast with int(), because everything read from a text file is a string and comparing a string with 50 would fail. Using with open means the file is closed automatically even if an error occurs part way through.
- LWrite mode empties the existing file before writing
- LAppend mode adds new data to the end, keeping what is there
- LGives a suitable use of write mode, such as creating a fresh report
- LGives a suitable use of append mode, such as adding to a log of results
Opening a file in write mode, using "w", deletes everything already in the file before a single character is written, so the file always ends up containing only what this run of the program put there. Append mode, using "a", leaves the existing contents alone and adds the new data to the end. Write mode is appropriate when the file is being regenerated in full each time, for example a report that should reflect only the current data. Append mode is appropriate when each run adds to a growing record, for example a log file that records the result of every game played, where opening in write mode would destroy the entire history every time the program ran.