- Learn
- Computer Science & IT
- Programming
- Introduction to Programming with Python
- Python Exceptions and Files
Files and Exceptions in Python
with statements, and find files with relative and absolute paths and pathlib. Read and write CSV data with the csv module, including rows as dictionaries. Then catch the errors you expect with try and except, use else and finally, raise your own exceptions with clear messages, and build programs that report missing files and bad data instead of crashing.BeginnerLesson 8 of 10 in Python for Beginners: Introduction to Programming
What you will learn
- Open text files, read their contents in the way that suits the task, write and add text without losing data, and process a file line by line to search, count and filter.
- Open a text file and read its contentsUse
open()to connect a program to a text file, choose the right way to read it, and turn the text you read into data you can use. - Close files automatically with the with statementUse
with open(...) as f:so that files are closed at the right moment, even when something goes wrong. - Write and add text to filesChoose the right mode to create, overwrite or extend a file, and write text with
write()andprint()so that lines come out exactly as intended. - Search, count and filter lines in a fileProcess a file one line at a time to find the lines you need, count or total them, and write the results to a new file.
- Open a text file and read its contents
- Tell Python exactly where a file is, understand why a program sometimes cannot find a file that exists, and build paths that work on Windows, macOS and Linux.
- Use relative and absolute paths correctlyWrite absolute and relative paths, know which folder a relative path starts from, and avoid the backslash traps of Windows paths.
- Build paths and manage folders with pathlibUse
Pathobjects from thepathlibmodule to join, inspect and check paths, find files, create folders and read or write small files in one step.
- Use relative and absolute paths correctly
- Use Python's
csvmodule to read table data from CSV files, convert it to numbers, and write results back as CSV that spreadsheet programs can open.- Read CSV data with csv.readerUnderstand how a CSV file stores a table, read it row by row with
csv.reader, skip the header and convert the values you need. - Write CSV files with csv.writerCreate CSV files from lists with
csv.writer, so that commas, quotes and line endings are handled correctly. - Work with columns by name using DictReader and DictWriterRead each CSV row as a dictionary keyed by the header, filter and summarize rows by column name, and write dictionaries back to CSV.
- Read CSV data with csv.reader
- Recognize the exceptions Python raises, read a traceback to find the cause, catch the errors you expect, and keep a program running or stop it with a clear message instead of a crash.
- Recognize common exceptions and read a tracebackKnow what an exception is, read a traceback from the bottom up, and name the common exception types with what typically causes each.
- Catch exceptions with try and exceptWrite
tryandexceptblocks that catch the specific errors you expect, give the user a useful message, and let unexpected errors still show up. - Use else and finally, and follow exceptions through functionsComplete a
trystatement withelseandfinally, predict the order in which its blocks run, and decide in which function an exception should be handled. - Make file and data programs fail gracefullyCombine file handling and exception handling so that missing files, blocked files and bad data lead to clear messages, skipped rows or a clean stop instead of a crash.
- Recognize common exceptions and read a traceback
- Use
raiseto stop a function from continuing with bad input, choose fitting exception types and messages, and pass errors on or turn them into clearer ones.- Raise exceptions to reject bad inputUse the
raisestatement to signal that a function received a value it cannot work with, and let the caller decide how to respond. - Re-raise, chain and define custom exceptionsPass an exception on after reacting to it, turn a low-level error into a clearer one, and create your own exception types for problems specific to your program.
- Raise exceptions to reject bad input
Python Exceptions and Files study guide
1Read and write text files
Files let a program keep information between runs and work with data collected elsewhere. Reading brings text into memory; writing saves results for the next run or another person. You will choose a reading method, control exactly what is written, and use indentation to keep files open only while they are needed. Line-by-line examples then combine string operations, decisions, and counters to turn raw text into useful results.
1.1 Reading text into a program
A text file keeps information after a program stops. Python uses a file object, returned by open(), to work with that information. Opening connects to the file; a reading operation retrieves its text.
Choose what to read
The default mode is "r", for reading. A bare name is looked up in the current working directory. If it is missing there, open() raises FileNotFoundError.
with open("fruit.txt", encoding="utf-8") as f:
text = f.read()
Suppose the file has three lines, "apple", "banana", and "cherry", all with line endings. text is 'apple\nbanana\ncherry\n'. The escape \n represents one newline character. A last line can also end without a newline.
| Operation | Result | Useful when |
|---|---|---|
f.read() | All remaining text as one string | You need a small file as a whole |
f.readline() | The next line as a string | You need one line now |
f.readlines() | All remaining lines as a list | You need to reuse the lines |
for line in f: | One line per pass | You can process lines in order |
readline() returns '' at the end of the file. A blank line that has a line ending returns '\n', so a blank line and the end of the file are different.
Keep track of the position
Reading moves the file's position forward. After f.read() has consumed the file, another call returns ''; a loop over that same object has nothing left. Reopen the file to start again, or keep the needed text or lines in a variable. read() and readlines() load the remaining file into memory. Looping directly over the file lets you process a large file one line at a time.
Lines retain their newline characters. print(line) adds its own newline, which can leave extra blank lines on screen. Use print(line, end="") to keep the original spacing, or remove the line ending before printing. line.rstrip("\n") removes trailing newlines; line.strip() also removes spaces at both ends.
Turn text into numbers
Even digits arrive as strings. This file contains the scores "72", "85", and "90":
scores = []
with open("scores.txt", encoding="utf-8") as f:
for line in f:
scores.append(int(line))
total = sum(scores)
print(total, round(total / len(scores), 2))
The list is [72, 85, 90], so the program prints 247 82.33. int() accepts surrounding spaces and newlines. An empty string or a word such as "forty" raises ValueError.
Read characters with the right encoding
An encoding maps characters to stored bytes. UTF-8 can represent characters such as "é" and emoji. Use encoding="utf-8" explicitly for UTF-8 files. Python 3.15 enables UTF-8 mode by default; older installations may use a local encoding. An incorrect encoding can produce garbled text or UnicodeDecodeError. Explicit encoding does not convert a file saved in another encoding into UTF-8.
The with block closes the file when it ends. A closed file cannot be read: another f.read() raises ValueError.
Key Takeaways
open()returns a file object; reading retrieves text from its current position.- Choose a string, a list of lines, or a line-by-line loop to fit the task.
- End of file gives
''; a blank line can give'\n'. - Convert numeric text with
int()orfloat()before calculating. - Use the encoding that matches the file, and close it when finished.
1.2 Files that close when the block ends
An open file uses operating-system resources. Text being written can also wait in a memory buffer before it reaches the file. Closing releases the resources and flushes buffered output. A with statement arranges that cleanup at a clear place in the code.
Read inside, use the result afterward
with open("notes.txt", encoding="utf-8") as f:
text = f.read()
print(len(text))
The colon starts the block. The indented line runs while f is open. When execution reaches the unindented print(), the file has closed, but text remains an ordinary string. The name f still refers to the file object; f.closed is now True.
The same pattern works for a list:
with open("fruit.txt", encoding="utf-8") as f:
lines = f.readlines()
for line in lines:
print(line.strip().upper())
The loop uses data already read into lines. Moving f.readlines() outside the block would try to read a closed file and raise ValueError.
Cleanup when execution changes direction
Consider a function that returns the first line:
def first_line(path):
with open(path, encoding="utf-8") as f:
return f.readline().rstrip("\n")
The return value is prepared inside the block. Python then leaves the block and closes the file before the caller receives that value. The file also closes when an exception leaves the block. A manual f.close() placed after a failing statement would never be reached.
File objects support this behavior because they are context managers: objects that arrange setup and cleanup around a with block. You can use that behavior without writing a context manager yourself.
Open an input and an output together
with open("in.txt", encoding="utf-8") as src, open("out.txt", "w", encoding="utf-8") as dst:
for line in src:
dst.write(line.upper())
Each input line is converted to uppercase and written to the output. Both files close when the block ends. If the second opening fails, the first file, already entered by with, is closed as Python leaves the statement.
Cleanup and recovery do different jobs
with does not catch file errors. If open() cannot find notes.txt, it raises FileNotFoundError before the body runs. If converting a line with int() fails inside the body, the file closes and the exception continues outward. A matching except clause is needed to recover or show a message.
A missing colon at the end of the with line causes SyntaxError.
Key Takeaways
withcloses an opened file on normal exit, return, and exception exit.- Stored strings and lists remain usable after the file closes.
- Indentation marks the lifetime of the open file.
- Cleanup does not catch an exception; recovery needs
tryandexcept.
1.3 Creating, replacing, and appending text
Writing begins with a choice about existing data. The mode controls whether Python reads, replaces, extends, or creates a file. Make that choice before calling open(), because replacement happens immediately.
Choose the mode
| Mode | Existing file | Missing file |
|---|---|---|
"r" | Opens for reading | Raises FileNotFoundError |
"w" | Empties, then opens for writing | Creates it |
"a" | Adds output at the end | Creates it |
"x" | Raises FileExistsError | Creates it |
Opening the only copy of important data with "w" destroys its old contents even if no write() follows. Use a separate output file while learning to transform data. "x" is useful when replacing an existing file must be refused.
Adding "b", as in "rb", selects binary mode for raw bytes. Text modes work with strings and an encoding; binary modes take no encoding argument.
Decide where lines end
with open("todo.txt", "w", encoding="utf-8") as f:
f.write("buy milk\n")
f.write("call Sam\n")
The file has the two lines "buy milk" and "call Sam". write() adds exactly the supplied string, with no automatic separator. Without the newlines, the file would contain "buy milkcall Sam" on one line.
write() returns the number of characters written. For example, f.write("Ana,92\n") returns 7. That is a character count, not necessarily the number of encoded bytes on disk. It accepts a string; f.write(42) raises TypeError. Convert a number first, for example with f.write(f"{score}\n").
Compare the output helpers
print() can write to a file:
with open("total.txt", "w", encoding="utf-8") as f:
print("Total:", 247, file=f)
The output text is "Total: 247\n". print() converts its arguments, separates them with spaces, and adds a final newline by default.
writelines() takes a sequence of strings but inserts no line endings. f.writelines(["a", "b"]) writes "ab". To get one item per line, include a newline in each string, or join the strings with "\n" and add a final newline.
Keep earlier runs
with open("log.txt", "a", encoding="utf-8") as f:
f.write("Program started\n")
Starting with no file, two runs produce two lines. With "w", each run would replace the earlier entry. Append mode does not supply a missing newline: if the existing text ends mid-line, the new text begins immediately after it.
For a report, loop over pairs such as [("Ana", 92), ("Ben", 78)] and write f"{name}: {score}\n". Formatting happens before writing, so f"{82.333:.1f}" produces the text "82.3". with then closes the output and flushes buffered text at the end of the block.
Key Takeaways
"w"empties an existing file as soon as it opens."a"adds at the end;"x"refuses to replace an existing file.write()takes a string and adds no newline.print(..., file=f)converts values and adds a newline by default.writelines()writes strings consecutively without adding separators.- Binary modes read or write bytes and take no encoding argument.
1.4 Finding and saving useful lines
Many file tasks are a loop with a decision inside it. Read a line, remove unwanted spacing, decide whether it matters, and update a result. Keeping these steps separate makes a program easier to check.
Work through a log
Suppose server.log contains these records, with a blank line before the last one:
2026-03-01 08:14 INFO Server started
2026-03-01 08:20 ERROR Disk almost full
2026-03-01 09:02 INFO User login: maya
2026-03-01 09:15 WARNING Slow response
2026-03-01 10:40 ERROR Database timeout
2026-03-01 11:05 INFO Backup finished
Each nonblank record has a date, time, level, and message. Split only three times to leave the message together:
errors = 0
with open("server.log", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
parts = line.split(maxsplit=3)
if parts[2] == "ERROR":
errors += 1
print(parts[3])
print(errors, "errors")
For the second record, parts[2] is "ERROR" and parts[3] is "Disk almost full". That message prints and the counter rises to 1. The later error raises it to 2. The program prints both messages and then "2 errors".
Match the intended part
| Test | What it asks |
|---|---|
line.startswith("From:") | Does the line begin with this text? |
"ERROR" in line | Does this text occur anywhere? |
line.find("ERROR") | Where is its first occurrence, or is the result -1? |
parts[2] == "ERROR" | Is this particular field exactly the error level? |
Searching anywhere would also match "INFO No ERRORS today". Checking the level field answers the log question more precisely.
After strip(), a blank line is ""; splitting it gives []. Indexing parts[2] would then raise IndexError. The continue skips that line before any indexing. A nonblank but incomplete record also needs a length check when such records are possible.
Count categories or write a filtered file
A dictionary holds a count per level. For each record, set level = parts[2] and then counts[level] = counts.get(level, 0) + 1. For the log above, the counts are {'INFO': 3, 'ERROR': 2, 'WARNING': 1}. The default 0 starts a category the first time it appears.
To save matching records, open a separate destination in the same with statement and write a line when its level matches. Keep the original line if the spacing matters; if you write cleaned text, put its newline back. Never open the source itself with "w": it would be emptied before reading begins.
See invisible characters
print(repr(line)) makes trailing spaces and newlines visible, for example 'Disk full \n'. strip() removes both, while rstrip("\n") keeps the spaces. Normal text reading translates recognized Windows, Unix, and old Mac line endings to "\n". A last line without an ending stays without one. A file name collected by input("File name: ").strip() lets the same loop work on different input files.
Key Takeaways
- Clean, select, process, and report in separate steps.
- Skip blank lines before indexing split fields.
- Match the intended field when a whole-line search could match too much.
- Use a dictionary to keep one counter per category.
- Write filtered output to a different file.
repr()reveals spacing and newline characters hidden in normal printing.
2Find files with paths
A correct file name is only part of a location. The folder where a program starts affects relative paths, and it can differ from the folder holding the script. You will trace paths through a folder tree, avoid Windows string escapes, and build locations with pathlib. These skills help explain missing-file errors and let the same project find its data and prepare output folders on different computers.
2.1 Where Python looks for a file
A path describes a location in a tree of folders. It can begin at the root of that tree or at the program's current working directory. A file can exist on the computer and still be missing at the location your program asks for.
Read a path from its starting point
| Kind | Example | Starting point |
|---|---|---|
| Absolute, macOS or Linux | /Users/maya/data/notes.txt | The root / |
| Absolute, Windows | C:/Users/Maya/data/notes.txt | The root of drive C |
| Relative | data/notes.txt | Current working directory |
Suppose a folder called project contains a scripts folder and a data folder. You run python scripts/report.py while working in project. Opening "data/notes.txt" looks inside project/data, even though the script is inside project/scripts.
If you instead start the same script while working inside project/scripts, that relative path points inside project/scripts/data. The script has not moved; the starting point has changed.
from pathlib import Path
print(Path.cwd())
This prints the current working directory. os.getcwd() after import os provides the same information as a string. Editors and launch tools can choose a working directory, so inspect it when the location is unclear.
Move through folders
In a relative path, . means the current folder and .. means its parent. From project/scripts, ../data/notes.txt goes up to project and then down into data. Adding .. without checking the starting folder can send a program to the wrong location.
An absolute path is useful for identifying one exact location, but a path such as C:/Users/Maya/Desktop/data.csv ties shared code to one person's folders. Use a relative path with a clear starting point, or build from the script's own folder when that is where the data belongs.
Keep Windows backslashes intact
Windows commonly displays backslashes between folders. In an ordinary Python string, a backslash begins an escape: \n becomes a newline and \t a tab. The literal "C:\new\table.txt" therefore does not contain the path you intended.
These forms preserve the intended path:
raw = r"C:\new\table.txt"
escaped = "C:\\new\\table.txt"
forward = "C:/new/table.txt"
Python on Windows accepts forward slashes. A raw string keeps backslashes from becoming escapes, but it cannot end in a single backslash. For example, r"C:\data\" is invalid syntax.
Check the name as well as the folder
Look for spelling differences and hidden extensions: a file displayed as "notes.txt" may actually be named "notes.txt.txt". Letter case also matters. Linux commonly distinguishes Data.csv from data.csv; usual Windows and macOS settings do not. Matching the actual case keeps a project usable across systems.
Key Takeaways
- Relative paths start from the current working directory.
- The working directory can differ from the script folder.
.stays in the current folder;..moves to its parent.- Use raw strings, doubled backslashes, or forward slashes for Windows paths.
- Check exact names, extensions, and letter case when a file is missing.
2.2 Building paths with pathlib
The standard pathlib module gives a path its own object. A Path lets you join folder names, inspect a file name, and do common file tasks without manually building separator strings.
Join and inspect
from pathlib import Path
p = Path("reports") / "2026" / "sales.csv"
print(p.name)
print(p.stem)
print(p.suffix)
print(p.parent)
The first three results are "sales.csv", "sales", and ".csv". The parent is the path reports/2026, displayed with the system's separator. Here / joins path parts; it does not divide numbers. The older os.path.join() joins string path parts too.
A Path describes a location even before anything exists there. p.exists() checks for something at that location. p.is_file() and p.is_dir() distinguish a file from a directory. An existence check cannot guarantee a later opening: the file may disappear or access may change between those operations. Handle opening errors when the program needs to recover.
Read or write a small file
open() accepts a Path directly. For a small file, these helpers also manage opening and closing:
p = Path("greeting.txt")
p.write_text("Hello\n", encoding="utf-8")
text = p.read_text(encoding="utf-8")
text becomes "Hello\n". write_text() replaces existing contents, just like opening with "w"; it is not an append helper. read_text() loads the whole file, so use a file loop when you need to handle a large file line by line.
Start from the script folder
A data file supplied beside a script should be located from that script, independent of the working directory:
base = Path(__file__).resolve().parent
scores_path = base / "data" / "scores.txt"
with open(scores_path, encoding="utf-8") as f:
scores = f.readlines()
__file__ identifies the script file. resolve() makes its path absolute, and parent selects its containing folder. In an interactive shell, __file__ is not defined, so this pattern belongs in a script.
Find files and prepare output folders
for p in sorted(Path("logs").glob("*.txt")):
text = p.read_text(encoding="utf-8")
print(p.name, len(text.splitlines()))
glob("*.txt") selects matching paths in logs. iterdir() produces the folder's entries without that pattern filter. Sorting makes the order predictable. splitlines() counts the text lines without treating the final line ending as an extra empty line.
Writing creates a file, but not missing parent folders. Prepare them first:
folder = Path("output") / "daily"
folder.mkdir(parents=True, exist_ok=True)
(folder / "report.txt").write_text("Ready\n", encoding="utf-8")
parents=True creates missing folders above daily. exist_ok=True accepts an already existing directory. It does not turn an existing ordinary file into a folder.
Key Takeaways
Pathjoins parts with/and works directly withopen().name,stem,suffix, andparentexpose different path parts.- An existence check cannot guarantee a later open will succeed.
read_text()reads all text;write_text()replaces it.- Build from
Path(__file__).resolve().parentfor script-relative data. - Use
glob()to find matches andmkdir()to create missing folders.
3Read and write CSV files
Table data needs more structure than a collection of lines. A name may contain a comma, a field may contain a line break, and a quantity still arrives as text. You will use the CSV module to preserve those boundaries, convert values for calculations, and write results that another program can read. Named columns make processing clearer, while checks on headers and row shapes help expose incomplete data.
3.1 Reading CSV rows and fields
A CSV file stores a table as text. Its records are rows, and its fields are column values. Commas commonly separate fields, but quoted fields can contain commas and even line breaks. Use the csv module to keep those values together.
Let a reader handle quotes
name,quiz1,quiz2
Ana,8,9
Ben,7,6
"Lopez, Maria",10,8
The first row is a header, containing column names. The last data row has three fields, not four: the comma inside the quoted name belongs to the name. A double quote inside a quoted field is written twice. Splitting each line with split(",") would ignore those rules and break the name into pieces.
import csv
with open("grades.csv", newline="", encoding="utf-8") as f:
reader = csv.reader(f)
header = next(reader)
for row in reader:
average = (int(row[1]) + int(row[2])) / 2
print(row[0], average)
The reader returns lists of strings. next(reader) consumes the header once, leaving the loop to process data. The program prints "Ana 8.5", "Ben 6.5", and "Lopez, Maria 9.0". In the first data row, converting "8" and "9" gives 17 in total, then dividing by 2 gives 8.5.
Keep file handling and table parsing aligned
Open CSV files with newline="" so the csv module handles line endings itself. This matters when a quoted field includes a line break. One CSV record can span several physical file lines, so a line-by-line split is not a substitute for a CSV reader.
The reader's default behavior leaves values as strings. Without conversion, adding row[1] + row[2] joins "8" and "9" into "89". Forgetting to skip the header instead tries to convert "quiz1" and raises ValueError.
If a file might be empty, next(reader, None) consumes a header when present and returns None otherwise. A completely blank CSV line becomes []. Skip such rows with if not row: continue before indexing. A nonblank row with too few fields also needs a length check; skipping only blank rows will not protect row[2] from every short record.
Match the file's format
reader = csv.reader(f, delimiter=";", skipinitialspace=True)
This selects semicolons as separators and removes spaces immediately after them. Choose the separator the file actually uses; changing the separator does not convert decimal commas into decimal points. float("2,50") still raises ValueError.
Some spreadsheet exports begin with a UTF-8 byte order mark. Reading one with encoding="utf-8" can leave "\ufeff" at the beginning of the first field, turning the header "name" into "\ufeffname". For that format, encoding="utf-8-sig" removes the marker; it can also read UTF-8 files without one.
Key Takeaways
- A CSV record can contain quoted commas or line breaks.
- Use
csv.reader, not a plain comma split, to respect quoting. - Open CSV files with
newline=""and a matching encoding. - The default reader returns strings; skip a header before numeric conversion.
- Check empty or short rows before accessing fields.
- Select the correct delimiter and handle a byte order mark when present.
3.2 Writing table rows as CSV
A CSV writer turns values into correctly separated and quoted fields. Give it rows as sequences of values and let it handle punctuation. This avoids output that looks right until a name or message contains a comma.
Write a header and data
import csv
with open("summary.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["name", "average"])
writer.writerow(["Ana", 8.5])
writer.writerow(["Lopez, Maria", 9.0])
The file has the rows name,average, Ana,8.5, and "Lopez, Maria",9.0. The writer converts numbers to text. It quotes the name with a comma and doubles any double quote inside a quoted field. None becomes an empty field, so reading the file back does not recover None automatically.
writerow() takes one row. writerows() takes a sequence of rows, such as [["Ana", 8.5], ["Ben", 6.5]]. Passing "Ana" directly to writerow() instead gives it three characters, producing A,n,a. Use ["Ana"] for a row with one field.
Give CSV control of line endings
Use newline="" when opening the output. The default writer ends records with "\r\n". Allowing text-mode newline translation as well can add an extra carriage return on Windows, producing unwanted blank lines in some readers. The newline argument prevents that second layer of translation.
Transform one file into another
with open("grades.csv", newline="", encoding="utf-8") as src, open("summary.csv", "w", newline="", encoding="utf-8") as dst:
reader = csv.reader(src)
writer = csv.writer(dst)
next(reader)
writer.writerow(["name", "average"])
for row in reader:
average = (int(row[1]) + int(row[2])) / 2
writer.writerow([row[0], round(average, 2)])
For the grades rows "Ana,8,9", "Ben,7,6", and "Lopez, Maria",10,8, the averages are 8.5, 6.5, and 9.0. The reader removes CSV quoting from the input field value; the writer adds the necessary quoting again in the output. round() controls the numeric value written, though it does not force two displayed decimal places. Use a format such as f"{average:.2f}" when exactly two places are wanted.
Append without repeating the header
Before opening an append file, check whether it needs a header:
from pathlib import Path
p = Path("sales.csv")
needs_header = not p.exists() or p.stat().st_size == 0
with open(p, "a", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
if needs_header:
writer.writerow(["item", "quantity"])
writer.writerow(["coffee", 4])
An existing empty file also needs its header. Writing the header on every run puts column names in the middle of data. This pattern assumes one program is updating the file; an existence check does not reserve it against other programs changing it.
Key Takeaways
- Pass a sequence of fields to
writerow()and rows towriterows(). - The writer converts values and handles quoting;
Nonebecomes an empty field. - Use
newline=""for CSV output as well as input. - Append a header only when the file is new or empty.
3.3 Using column names in CSV code
Position-based code such as row[2] depends on column order. A dictionary-based reader lets you name the value you need. A dictionary maps keys to values; here the header supplies the keys and each data record supplies their values.
Read fields by name
import csv
with open("inventory.csv", newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
rows = list(reader)
For the header product,stock,price and row notebook,12,2.50, the first dictionary is {'product': 'notebook', 'stock': '12', 'price': '2.50'}. reader.fieldnames gives the header names. The header is consumed automatically; calling next(reader) would skip the first data record.
Use row["stock"] to select stock, even if the columns are reordered. Convert it with int() to compare quantities. The values remain strings; column names do not give the reader numeric types.
Filter and total
Suppose the table contains notebook stock 12 at price 2.50, pen stock 3 at 1.20, stapler stock 0 at 7.95, and folder stock 25 at 0.80.
low = [r for r in rows if int(r["stock"]) < 5]
value = sum(int(r["stock"]) * float(r["price"]) for r in rows)
low holds the pen and stapler rows. The value is 53.6 dollars: notebook contributes 30, pen 3.6, stapler 0, and folder 20. The filter uses stock, while the total uses both stock and price.
Distinguish missing keys from missing values
Header names must match exactly. Name and name are different keys. A space after a comma can become part of a header; skipinitialspace=True removes spaces immediately following separators.
A header name,quiz1,quiz2 with data Ben,7 produces {'name': 'Ben', 'quiz1': '7', 'quiz2': None}. The key exists, but its value is missing. int(None) raises TypeError. A present empty field is "", and converting that raises ValueError. A key absent from the header instead causes KeyError on lookup.
With data Cara,1,2,3, extra fields are collected as None: ['3']; the named fields still contain "Cara", "1", and "2". Check the shape of a row when accurate totals depend on every field.
Write selected columns
with open("reorder.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["product", "stock"])
writer.writeheader()
for r in low:
writer.writerow({"product": r["product"], "stock": r["stock"]})
fieldnames sets the output order, regardless of dictionary order. Missing dictionary keys become empty fields. Extra keys raise ValueError by default: passing an inventory dictionary containing price to this two-column writer fails. Build the smaller dictionary as shown, or choose extrasaction="ignore" when dropping extra fields is intentional.
Key Takeaways
DictReaderconsumes the header and returns dictionaries of string values.- Header names must match the lookup keys exactly.
- A missing field defaults to
None; an empty present field is"". - Extra fields go under the key
Noneby default. DictWriterneedsfieldnamesto set column order.- Missing output keys become empty fields; unexpected keys raise
ValueErrorby default.
4Handle errors with try and except
File names can be wrong, access can be denied, and a numeric column can contain a word. An exception marks the point where normal execution cannot continue. You will read error reports, catch expected problems, and keep success work separate from cleanup. Following errors through function calls then helps you put recovery where it can make a useful decision, including retrying a read or reporting a rejected row.
4.1 Understanding an error report
An exception is an object that signals a problem during execution. Raising it interrupts normal execution. If no handler deals with it, Python ends the program with a traceback, a report of the calls that led to the error.
Start at the bottom
def average(values):
return sum(values) / len(values)
def report():
scores = []
print(average(scores))
report()
The traceback ends with ZeroDivisionError: division by zero. Start there: the type names the kind of problem and the message gives detail. The entry immediately above points to the division in average(). Earlier entries show the call from report() and the original call to report(). The list is empty, so its length is 0. The reported failing line is where the problem appears; the earlier empty-list assignment explains how it arose.
Choose the matching type
| Type | Typical cause |
|---|---|
ValueError | int("3.5"): a string with an unacceptable value |
TypeError | len(5): an operation on the wrong kind of object |
ZeroDivisionError | Dividing by zero |
IndexError | Reading a list position that does not exist |
KeyError | Looking up a missing dictionary key |
NameError | Using an undefined name |
AttributeError | Asking an object for an attribute it lacks |
int("abc") receives an allowed input type, a string, but cannot interpret that value as an integer. "5" + 3 instead mixes incompatible types for addition. A string that contains digits is still a string.
File operations have more specific types: FileNotFoundError for a missing path, PermissionError for denied access, and FileExistsError for creating an existing file with "x". Opening a directory as an ordinary file can raise IsADirectoryError. Decoding bytes with an incompatible encoding can raise UnicodeDecodeError.
Understand the family tree
Exception classes form a hierarchy. A handler for a parent class can catch its child classes:
OSErroris the parent of common file-system errors, includingFileNotFoundErrorandPermissionError.LookupErroris the parent ofIndexErrorandKeyError.ArithmeticErroris the parent ofZeroDivisionError.UnicodeDecodeErrorbelongs underValueError.
These branches descend from Exception, which descends from BaseException. KeyboardInterrupt and SystemExit instead descend directly from BaseException. That distinction lets except Exception leave user interruption and program exit alone.
Separate syntax, runtime, and logic problems
A missing colon or closing parenthesis can stop Python from parsing a script. The resulting SyntaxError occurs before the script runs, so a try in that same script cannot catch it. A runtime exception occurs while valid code executes. A logic error produces a wrong answer without necessarily raising any exception, such as dividing a total by the wrong count.
Key Takeaways
- Read the exception type and message at the bottom of a traceback first.
- Use the call entries to trace the failing value back to its origin.
ValueErrorconcerns an unacceptable value;TypeErrorconcerns an unsuitable type.- A parent exception handler also catches child exception classes.
- Syntax, runtime, and logic errors happen in different ways.
4.2 Catching a problem where it can be handled
A try statement runs risky code and gives selected exceptions a recovery path. The handler should match the problem the program expects and knows how to respond to.
Follow the flow
while True:
try:
age = int(input("Age: "))
break
except ValueError:
print("Please enter a whole number, like 34.")
print("Next year you will be", age + 1)
Typing "twenty" makes int() raise ValueError. Python skips the rest of the try, including break, and runs the matching handler. The loop then asks again. Typing "34" lets the try finish through break, so the program leaves the loop and prints "Next year you will be 35".
A handler does not resume at the failed statement. Execution proceeds after the try statement unless the handler itself changes that flow. If no handler matches, the exception travels outward.
Handle different failures differently
try:
result = int(a) / int(b)
except ValueError:
print("Both values must be whole numbers.")
except ZeroDivisionError:
print("The second value cannot be 0.")
A bad conversion and a zero divisor need different messages. If the response should be identical, group types in a tuple: except (ValueError, ZeroDivisionError):. Parentheses work throughout Python 3. Python 3.14 also permits an unparenthesized list when there is no as part; the tuple form remains clear across versions.
Python checks clauses from top to bottom and runs the first match. Put FileNotFoundError before its parent OSError if a missing file needs a special response. Reversing them makes the special handler unreachable.
Use the message without hiding other bugs
try:
quantity = int(text)
except ValueError as err:
print("Cannot read quantity:", err)
err is the exception object; printing it shows its message. type(err).__name__ gives its class name. Python deletes the handler's err binding when the handler ends, so copy its message to another variable inside the block if it is needed later.
Keep the try small. Put later calculations outside the conversion handler when their failures would need different treatment. except Exception: can hide bugs such as an undefined variable. A bare except: is broader still: it also catches KeyboardInterrupt and SystemExit.
Retry the operation, not a rough imitation
Testing text.isdigit() does not test everything int() accepts. "-5" and " 34" fail that test but convert successfully; "²" passes it but does not convert with int(). Trying the conversion and catching ValueError uses the conversion's own rules.
Do something visible or recorded when handling bad data. An empty except ValueError: pass can leave the program continuing with missing results and no account of what went wrong.
Key Takeaways
- An exception skips the remaining
trycode and runs the first matching handler. - Use specific types and put child-class handlers before parent handlers.
- Group types in a tuple when their recovery action is the same.
except ... as errgives access to the message inside the handler.- Keep the
tryfocused so messages describe the actual failing operation. - Try numeric conversion directly when you need to test what it accepts.
4.3 Success, cleanup, and errors between functions
A try statement can separate the risky operation, recovery, success work, and cleanup. An exception can also leave one function and be handled by its caller.
Give success work its own block
try:
x = 10 / int(text)
except ValueError:
print("not a number")
except ZeroDivisionError:
print("zero")
else:
print("result", x)
finally:
print("done")
With text = "4", the program prints "result 2.5" and "done". With "abc", it prints "not a number" and "done"; with "0", it prints "zero" and "done".
else runs when the try completes normally without an exception. It does not run after a handler recovers from an error. It is also skipped when return, break, or continue leaves the try early. Errors raised inside else are not caught by that statement's earlier except clauses, so success work does not accidentally share the risky operation's handlers.
Let cleanup run on every exit path
finally runs as control leaves the statement: after success, after a handled exception, and before an unhandled exception travels onward. It also runs before a pending return completes.
def label():
try:
return "from try"
finally:
print("finally ran")
value = label()
print(value)
This prints "finally ran" and then "from try". The return was waiting while cleanup ran. For files, with already supplies closing behavior, so it usually removes the need for a manual finally close.
Do not put an exit such as return, break, or continue in finally. Leaving the cleanup block that way can discard a pending exception or override a return. Python 3.14 and later issue a SyntaxWarning for this pattern. Keep cleanup as cleanup.
Follow an exception to its caller
def read_scores(path):
with open(path, encoding="utf-8") as f:
return [int(line) for line in f]
try:
scores = read_scores("scores.txt")
except FileNotFoundError:
print("The score file is missing.")
If opening fails, read_scores() has no handler, so FileNotFoundError propagates to the call inside the outer try. The caller handles it and prints the message. If a line is not an integer, a ValueError follows the same route, but the missing-file handler does not match it.
Choose the level with a useful response
A reading function may know how to obtain data but not whether a missing file should trigger a retry, a skipped task, or a clean stop. Letting the exception reach the user-facing caller leaves that choice there. Catching it too early and returning an empty list can hide the difference between an empty file and a failed read.
Key Takeaways
elseruns only after normal completion of thetrybody.finallyruns before control leaves, including on return or an unhandled exception.- An exception in
elseis outside the preceding handlers in that statement. - Avoid exits from
finallythat can discard pending errors or returns. - Unhandled exceptions propagate through calls to a matching outer handler.
4.4 Recovering from file and row errors
A program fails gracefully when it responds to a problem in a controlled, useful way. It can ask again, report a skipped row, or stop with a clear message. Choose that response according to what the result will be used for.
Retry a missing file
while True:
name = input("File name: ").strip()
try:
with open(name, encoding="utf-8") as f:
text = f.read()
except FileNotFoundError:
print(f"No file named '{name}'. Please try again.")
else:
break
print(len(text.splitlines()), "lines")
A failed opening skips the assignment and reaches the handler. The loop asks again. A successful read reaches else, breaks the loop, and leaves text available for the final count. The file is closed by with on either exit from an entered block.
For different file problems, use FileNotFoundError, then PermissionError, then a general OSError handler if other file-system errors need a response. The specific clauses must come first. Decoding bad bytes is a different problem; a message about a missing path would not describe it.
Handle each data row separately
For a quick sales summary, suppose the CSV rows after the header are coffee,4, tea,two, muffin,3, cookie,, and juice,5.
import csv
total = 0
skipped = 0
with open("sales.csv", newline="", encoding="utf-8") as f:
reader = csv.reader(f)
next(reader, None)
for row in reader:
try:
if len(row) != 2:
raise ValueError("expected two fields")
quantity = int(row[1])
except ValueError as err:
skipped += 1
print(f"sales.csv, ending line {reader.line_num}: {err}")
else:
total += quantity
print("Total:", total, "Skipped:", skipped)
The valid quantities total 12. The word "two" and the empty quantity are rejected, so the skipped count is 2. The row check also turns an unexpected field count into a reported data error before indexing. Placing try inside the loop lets the next record run after one fails; placing the loop inside a single try would leave the loop on its first failure.
Report locations accurately
For the five single-line records, the bad values end on file lines 3 and 5. enumerate(reader, start=2) would match those line numbers here, but a quoted line break makes a CSV record span more than one line. reader.line_num reports how many physical lines the reader has consumed. Calling it an ending line keeps messages accurate for multiline records.
Decide whether a partial result is acceptable
A quick exploratory count may allow reported skips. A financial or grade total may need every record: stop and ask for corrected data instead of presenting a partial total as complete. Name the file, location, and problem so it can be fixed.
After import sys, sys.exit("Could not open sales.csv") writes the message to error output and exits with status 1. It raises SystemExit, which except Exception does not catch. Keep handlers specific so an unrelated programming error is not mislabeled as a file problem.
Key Takeaways
- Choose retry, skip, or stop according to the task.
- Put row-level recovery inside the loop to continue after a bad row.
- Report skipped records and label partial results clearly.
- CSV record numbers can differ from physical line numbers.
sys.exit(message)ends with an error message and status 1.- Use specific handlers so the message matches the real problem.
5Raise your own exceptions
Functions need a clear way to report input they cannot handle. Raising an exception keeps a failed operation from producing a misleading result and lets the caller choose a response. You will choose meaningful types and messages, pass an existing error onward, and preserve its cause when translating it. A short custom-class pattern gives a program its own error type when callers need to distinguish one problem from another.
5.1 Rejecting input with raise
A function should signal when it cannot produce a valid result. raise starts an exception at that point, so the invalid path cannot carry on as though the operation succeeded.
Check before calculating
def withdraw(balance, amount):
if amount <= 0:
raise ValueError(f"amount must be positive, got {amount}")
if amount > balance:
raise ValueError(f"amount {amount} is more than the balance {balance}")
return balance - amount
withdraw(100, 30) returns 70. withdraw(100, 150) raises an error about the balance; withdraw(100, -5) raises an error about a nonpositive amount. Neither failing call reaches the subtraction.
A raised exception follows the same handling rules as a built-in error. If a matching handler inside the function catches it, execution can continue there. Otherwise the exception leaves the function and reaches the caller. If no handler is found, Python reports a traceback.
Let the caller choose the response
balance = 100
amount = 150
try:
balance = withdraw(balance, amount)
except ValueError as err:
print(f"Cannot withdraw: {err}")
The function reports why it cannot withdraw. The caller decides to display a message. Because the function call fails before returning, the assignment does not replace the old balance with a result. Another caller could ask for a smaller amount or cancel a transaction without changing the function.
Printing a warning inside the function and returning None instead can let the caller carry an invalid value into a later calculation. Raising keeps the failure attached to its cause and gives the caller a distinct error path.
Choose a meaningful type
| Problem | Suitable type |
|---|---|
| Correct kind of input, unacceptable value | ValueError |
| Wrong kind of object for the operation | TypeError |
A negative numeric amount has an unacceptable value. A list supplied where a number is required has an unsuitable type. The exception type is part of the function's behavior: callers use it to select handlers. Do not choose a type merely because it is familiar.
Write a useful message
A message should name what was expected and what arrived. f"age must be between 0 and 130, got {age}" points to a fix. A message such as "error" gives no usable detail. Keep the message about the failed operation; user-facing code can add the larger context.
raise ValueError("amount must be positive") creates an exception with a message. raise ValueError is also valid and creates one without a message. A plain string is not an exception: raise "error" raises TypeError because raised objects must derive from BaseException.
Key Takeaways
- Raise at the point where a function cannot continue correctly.
- Use
ValueErrorfor an unacceptable value andTypeErrorfor an unsuitable type. - Include the expected input and the received value in a helpful message.
- Let the caller decide how to respond to the failed operation.
5.2 Passing on and naming exceptions
Sometimes a function notices an error but cannot finish handling it. It may need to pass the same error onward, translate it into a more useful error, or give a specific program problem its own exception type.
Re-raise the current error
def read_text(path):
try:
with open(path, encoding="utf-8") as f:
return f.read()
except FileNotFoundError:
print(f"Missing: {path}")
raise
The bare raise inside the handler re-raises the current exception. Printing a message alone would finish the handler and leave the function returning None; re-raising makes the failed read visible to the caller. A bare raise needs an active exception to re-raise.
Translate while preserving the cause
def read_price(row):
try:
text = row["price"]
except KeyError as err:
raise ValueError("row has no 'price' column") from err
return float(text)
A missing key becomes a ValueError with a message about the row. from err records the original KeyError as its direct cause. The traceback shows the original error, the link between them, and the new error. The caller can handle the translated type while debugging still has the lower-level cause.
This handler is limited to the lookup. A present value such as "free" fails later at float(text) with its own ValueError; it is not falsely reported as a missing column.
Define a distinct type
class InsufficientFundsError(ValueError):
pass
This pattern creates a custom exception class. The name ends in Error by convention. The name in parentheses is its parent, so this class is a kind of ValueError.
def withdraw(balance, amount):
if amount > balance:
raise InsufficientFundsError(
f"balance {balance}, requested {amount}"
)
return balance - amount
try:
withdraw(100, 150)
except InsufficientFundsError as err:
print("Not enough money:", err)
The program prints "Not enough money: balance 100, requested 150". A caller can distinguish insufficient funds from another invalid value. If a ValueError handler appeared before this specific handler, the parent would catch it first.
Choose the parent for the intended handling
Deriving from ValueError allows both a specific handler and a broader value-error handler to catch the custom type. Deriving directly from Exception creates a separate ordinary-error branch, so except ValueError would not catch it. A custom type is useful when callers need a distinct response; a clear built-in type and message are enough when they do not.
Key Takeaways
- Bare
raisein a handler passes on the current exception. raise NewError(...) from errrecords the original error as a direct cause.- A custom exception gives callers a distinct problem type.
- The parent class determines which broader handlers can catch the custom error.
- Place a specific custom handler before its parent handler.
Python Exceptions and Files examples
1Turn a text file into a filtered report
13 steps
- 1IntroductionRead, decide, save
A support log contains one event per line. You want a new file containing just the events that need attention. That task combines reading, string checks, and writing.
First follow how a file supplies text. Then build the filter in small steps, keeping the input separate from the output and letting
withclose both files when processing ends. - 2ExplanationA file supplies strings
Suppose
events.txtcontains"INFO Ready\nERROR Queue full\n". Opening it creates a file object, not a copy of its text.f.readline()returns"INFO Ready\n". A second call returns"ERROR Queue full\n". A third returns""because the file is exhausted. The newline stays attached to a returned line; numeric text would also remain text until explicitly converted. - 3ChallengeChoose a reading method
A log may be much larger than available memory. You only need to inspect each line once. How should you read it, and why?
---reveal---
Loop directly over the open file with
for line in f:. It supplies one line at a time without requiring a whole-file string or list first. Callingread()orreadlines()would load the remaining contents into memory. - 4ExampleKeep the reading inside the block
with open("events.txt", encoding="utf-8") as f: first = f.readline() print(first.rstrip("\n"))The read happens while the file is open. Leaving the indented block closes it; the later print uses the saved string. This is why an operation on
firstcan happen afterward while anotherf.readline()cannot. - 5ChallengePredict cleanup after an error
Inside that file block, suppose
int("oops")raisesValueError. The surrounding code has no handler. Does the file remain open, and doeswithhide the error?---reveal---
The file closes as execution leaves the entered block. The error still propagates and produces a traceback if nothing catches it. Automatic cleanup protects the file’s lifetime; an
excepthandler would be needed to recover. - 6ExplanationChoose the output’s behavior
The filtered report should replace an older report, so open a different output path with
"w". That mode empties an existing file immediately.For an activity history that keeps earlier runs, use
"a". If an existing report must be protected from replacement, use"x"and handleFileExistsError. File creation still requires the containing folders to exist. - 7ExampleWrite exactly one line
To write a selected line, keep its original ending:
dst.write(line)If you instead cleaned it with
strip(), add the ending back:dst.write(cleaned + "\n")write()adds no separator.print(cleaned, file=dst)is another way to add a newline, whilewritelines()still expects supplied strings to contain any required endings. - 8ChallengePredict two runs
Starting with no file, a program runs twice. Each run opens
"runs.txt"in append mode and callsf.write("OK"). What text is saved?---reveal---
The file contains
"OKOK". Append mode keeps the first run, but neither the mode norwrite()adds a newline. Writing"OK\n"instead would make one line per run. Opening in"w"would leave only the latest"OK". - 9ExampleClean before selecting
Our log uses the first word as its level. Start each pass with:
cleaned = line.strip() if not cleaned: continue level = cleaned.split(maxsplit=1)[0]The empty-line check prevents indexing an empty list. Keeping the original
lineseparately lets output preserve its spacing. Only the cleaned copy is used to identify the level. - 10ChallengeCheck the right part
The log includes "INFO ERROR counter reset" and "ERROR Queue full". What level test saves only the second record?
---reveal---
Test
level == "ERROR"after extracting the first word. Searching for"ERROR"anywhere would also save the informational record because the word occurs in its message. The format tells you where to find the category you are selecting. - 11ExampleAssemble the filter
count = 0 with open("events.txt", encoding="utf-8") as src, open("urgent.txt", "w", encoding="utf-8") as dst: for line in src: cleaned = line.strip() if not cleaned: continue if cleaned.split(maxsplit=1)[0] == "ERROR": dst.write(line) count += 1 print(count, "saved")The counter changes only when a record is written. Both files close before the count is printed.
- 12ChallengeDiagnose a lost source
Someone changes the output name to
"events.txt", keeping"w". Why does the filter now risk saving nothing, even though the source opened first?---reveal---
The second opening empties the same underlying file before the loop reads it. The first file object has not saved a separate copy of the old text. Restore a different output path so the transformation cannot erase its input at opening.
- 13RecapTrace a file task before running it
For a file transformation, trace four decisions: where the input comes from, how much text is read at once, what selects a record, and what opening the output does to existing data.
Then check the block boundaries. File operations need open handles; saved strings, lists, and totals can be used after the handles close.
2Locate project data from any launch folder
9 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionFind the starting folder
- 2ExampleTrace a launch
- 3ChallengeChange the launch folder
- 4TipInspect before changing the path
- 5ExampleBuild from the script
- 6ExplanationPrepare a destination
- 7ChallengeInspect a name and find matches
- 8ChallengeCheck a proposed fix
- 9RecapSeparate location from availability
3Read a table and write a named-column report
13 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionPreserve the table’s structure
- 2ExampleRead one quoted record
- 3ExampleOpen and convert
- 4ChallengeRecognize a short row
- 5ExampleWrite values as fields
- 6ChallengeKeep one field together
- 7ExplanationUse the header as keys
- 8ExampleFilter by stock
- 9ChallengeDistinguish missing from empty
- 10ExampleExport selected columns
- 11ChallengeAppend a later batch
- 12TipMatch separators and encodings
- 13RecapCheck both structure and meaning
4Follow an error from a bad row to a useful response
15 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionChoose what can recover
- 2ExampleStart with the exception type
- 3ChallengeRecognize a different failure
- 4ExampleCatch only the expected conversion
- 5ChallengeOrder related handlers
- 6ExplanationGive success and cleanup separate jobs
- 7ChallengeTrace an unmatched error
- 8ConnectionLet a caller decide
- 9ExampleKeep recovery inside the record loop
- 10ExampleFollow three records
- 11ChallengeChange the loop boundary
- 12TipName the location correctly
- 13ChallengeChoose a complete result
- 14ExampleStop with an error status
- 15RecapPut each response at the right level
5Design a function’s error behavior
10 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionGive failure a clear path
- 2ExampleReject invalid requests
- 3ChallengeTrace a failed assignment
- 4ExplanationMatch the type to the problem
- 5ExampleName a distinct shortage
- 6ChallengeKeep the specific response reachable
- 7ExampleReact and pass the error onward
- 8ExampleTranslate a lower-level failure
- 9ChallengeChoose the right relationship
- 10RecapKeep the error meaningful to the caller
Python Exceptions and Files practice questions
Set 1: Reading files and tracing small programs10 Practice Questions
Question 1 of 10
"oak\npine". Immediately after opening it for reading, what does f.readline() return?Show answerHide answer
readline() returns the next line as a string and keeps its line ending, so the result is "oak\n". It does not remove the newline as strip() would. The second line has no final newline, but that does not change the first line.Question 2 of 10
The block finishes normally. What is printed?
with open("memo.txt", encoding="utf-8") as f:
text = f.read()
print(f.closed)
Show answerHide answer
with block closes the file, so f.closed is True. The name still refers to the file object; closure does not delete it. The stored string text remains usable, but the file cannot be read again through this closed object.Question 3 of 10
Show answerHide answer
"a", writes at the end and keeps existing text. Write mode, "w", would empty the log as soon as it opened. Append mode can also create a missing log, but the program must still include any needed newline in its message.Question 4 of 10
/work/lab. It runs python tools/count.py, which opens "inputs/list.txt". What absolute location does that relative path request?Show answerHide answer
/work/lab, so it requests /work/lab/inputs/list.txt. Running a script in tools does not automatically change the working directory to that folder. The script location and the process directory are separate starting points.Question 5 of 10
p = Path("exports/week/report.csv"), what is p.stem?Show answerHide answer
"report". The name property would keep the suffix and give "report.csv". The parent identifies the containing folder, while the suffix identifies the final extension.Question 6 of 10
csv.reader, what list is read from the record "River, West",6,8?Show answerHide answer
Question 7 of 10
writer.writerow("Leo") produce with the default comma delimiter?Show answerHide answer
writerow("Leo") treats each character as a field and writes L,e,o. For a single field containing the name, pass ["Leo"]. The writer expects a sequence of field values, not one unwrapped string.Question 8 of 10
"many". What exception does int(row["quantity"]) raise?Show answerHide answer
"many" is not a valid integer representation, so conversion raises ValueError. TypeError would describe an unsuitable input type such as None. The stated field rules out a missing-key error here.Question 9 of 10
What is printed?
def read_count(text):
return 12 / int(text)
try:
result = read_count("0")
print("read")
except ValueError:
print("bad text")
except ZeroDivisionError:
print("zero")
print("end")
Show answerHide answer
Question 10 of 10
-2, what is a suitable exception and message?Show answerHide answer
ValueError expresses that problem and the message identifies the expected range and received value. TypeError would incorrectly describe the kind of input.Set 2: Choosing methods and handling expected failures10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
What is printed?
def reserve(n):
if n <= 0:
raise ValueError("positive count required")
return n * 2
result = 7
try:
result = reserve(0)
except ValueError:
print(result)
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
except ValueError: block, what statement passes the same active exception on to the caller?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
"09:10 INFO ERROR count reset" and "09:12 ERROR Network down". The level is the second whitespace-separated field. What condition selects only error-level records?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
"12\n15\n". What pair results from first = f.read() followed by second = f.read() on one freshly opened reader?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
"C:\new\tasks.txt" fail to identify the intended file?Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
city,visitors and Mesa,24. After reader = csv.DictReader(f), the program calls next(reader) once and then loops. Why is Mesa absent from that loop?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
label;count, but the default CSV reader returns ["label;count"]. What reader setting matches this file?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
What is printed?
try:
value = 18 / int("0")
except ZeroDivisionError:
print("zero")
else:
print("success")
finally:
print("closed")
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
FileNotFoundError occurs in a try. The first handler is except OSError: print("file problem"), and the second is except FileNotFoundError: print("missing"). What prints?Show answerHide answer
Save this lesson to see this answer.
Set 3: Working through files and recovery paths10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
A file contains only "bad". What prints?
try:
with open("one.txt", encoding="utf-8") as f:
value = int(f.readline())
except ValueError:
print(f.closed)
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
f.writelines(["red", "blue\n"]), then opened once more in append mode to write "green\n". What text does it contain?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
results and results/daily are missing. What should run before writing Path("results/daily/run.txt").write_text("ok", encoding="utf-8")?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
not p.exists(). The path exists but has zero bytes. What condition also gives this file its needed header?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
DictReader has header name,first,second and reads Inez,5. What value is stored under "second", and what happens when it is passed to int()?Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
{"east": 4}["west"] raise?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
What does the caller receive, and what prints first?
def choose():
try:
return 11
finally:
print("leaving")
x = choose()
Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
try/except ValueError go?Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
class LimitError(ValueError): pass, a LimitError is raised. What happens if except ValueError: appears before except LimitError:?Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
parts = line.split(maxsplit=2). Records should have a date, level, and message, but some contain only a date. What check must precede parts[1] and parts[2]?Show answerHide answer
Save this lesson to see this answer.
Set 4: Diagnosing incomplete data and misleading handlers10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
f.readline() return?Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
data.txt contains three records. A program opens it with "r", then opens the same path with "w", and only then starts reading through the first handle. Why does this risk losing the input?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
p.exists() returns True, but the file is removed before open(p, encoding="utf-8"). What does a robust program still need at that opening?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
data/menu.txt next to its own location regardless of launch folder. What expression builds that path in the script?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
encoding="utf-8", its first header key is "\ufeffcode". What opening change removes the marker while preserving UTF-8 text?Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
{"title": "Map", "stock": "4", "cost": "3.50"}. A default DictWriter has fieldnames=["title", "stock"]. What happens when it writes the whole row unchanged?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
ValueError from int(text). That handler prints missing_name, which has never been defined. What happens to the new NameError?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
"North on physical line 2 and ends with Hall",7 on line 3. After reading it, what location does reader.line_num report?Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
None for a negative size. Its caller immediately multiplies the result by 4. Why would raising ValueError at validation improve this failure path?Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
KeyError as err, a handler runs raise ValueError("missing unit column") from err. What does the caller receive, and what cause is preserved?Show answerHide answer
Save this lesson to see this answer.
Set 5: Combining file processing with reliable error behavior10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
"10:00 INFO ERROR resolved", "10:01 ERROR Disk slow", and "10:02 ERROR Disk full". The second field is the level. After filtering by error level, how many records are saved?Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
/srv/course, runs tools/read.py, and opens "../shared/items.txt". What path does it request?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
["Vale, East", None, 3]. What record is produced, ignoring its final line ending?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
What prints before the error propagates?
try:
n = int("2")
except ValueError:
print("bad input")
else:
print("ready")
result = 9 / 0
finally:
print("cleanup")
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
with open("source.txt", encoding="utf-8") as src, open("new.txt", "x", encoding="utf-8") as dst:. The source opens, but new.txt exists. What happens to src and the body?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
int() accepts, including leading spaces and a sign. Why attempt int(text) in try instead of requiring text.isdigit() first?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
sys.exit("Required file unavailable") inside code covered by except Exception:. What happens?Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
total = 0 and skipped = 0. An inner handler skips a row if it has fewer than two fields or if int(row[1]) fails. It adds valid converted values to the total. For rows ["lamp", "8"], ["desk"], ["chair", "bad"], and ["shelf", "5"], what final pair is reported?Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
class ImportDataError(Exception): pass, a caller catches only ValueError. What happens when its helper raises ImportDataError?Show answerHide answer
Save this lesson to see this answer.
Stuck on your own question? Homework Help
Key Terms
A
Absolute path
/ on Unix-like systems or a drive root on Windows./Users/maya/data/notes.txt does not depend on the current working directory.Accumulator
errors starts at 0 and increases by 1 whenever the loop finds an error-level record.Append mode
"a" for run messages keeps previous runs, but the message still needs its own newline.AttributeError
"hi".push("!") raises AttributeError because a Python string has no method named push.B
Binary mode
"rb" identifies byte input, while text input uses a mode such as "r".Buffer
Byte order mark
encoding="utf-8-sig" removes the initial marker so the first header matches its intended name.C
Caller
Closed file
with block that opened a file as f ends, f.closed is True and f.read() raises a ValueError about closed-file access.Context manager
with block, such as opening access and cleanup.CSV
"Lopez, Maria",10,8 has three fields because its first comma is inside a quoted name.CSV writer
Current working directory
python tools/report.py from the project root does not by itself move into the tools folder.Custom exception
D
Delegated handling
Delimiter
delimiter=";" so a reader separates name;score into two fields.DictReader
name,score, a row can be accessed with row["score"] even if the columns are reordered.DictWriter
fieldnames=["product", "stock"] exports those columns when passed matching dictionaries.Directory creation
mkdir(parents=True) can also make missing folders above the requested one.output/daily before writing its report, since opening a new output file does not create folders.E
else clause
Encoding
Error message
Exception
int("many") conversion raises an exception before the next statement in that block runs.Exception binding
as so its type or message can be inspected within that handler.except ValueError as err:, printing err shows the message; the binding is deleted afterward.Exception chaining
raise ... from err.Exception handler
Exception hierarchy
Exclusive creation
FileExistsError if a file already exists there."x" prevents a newly generated report from silently replacing a report at the same path.Exit status
sys.exit("Missing input") prints the message to error output and ends with exit status 1.Extra field
None.F
Field
fieldnames
writeheader() on a DictWriter prints the names in its configured fieldnames order.File mode
open() that selects permitted access and how opening treats existing contents at the path."a" to keep earlier messages, while a fresh report may use "w" to replace them.File object
open() that gives a program methods for reading or writing an opened file.with open("notes.txt", encoding="utf-8") as f:, the name f refers to the file object.File position
f.read() has consumed the remaining contents, a second read returns an empty string.FileExistsError
"x" raises FileExistsError instead of replacing its contents.FileNotFoundError
finally clause
G
Glob pattern
* matching varying text inside the selected directory.Path("logs").glob("*.txt") finds matching text-file paths; sorting them gives a predictable processing order.Graceful failure
H
Header
product,stock,price names columns and should not be passed to integer conversion as data.I
IndexError
IsADirectoryError
K
KeyboardInterrupt
except: can catch Ctrl+C, while except Exception: leaves the interruption free to propagate.KeyError
row["name"] fails when the table’s header created the key "Name" instead.L
Line filter
"ERROR".Logic error
M
Missing field
None.name,score, the row Ana has a missing score; Ana, instead contains an empty score string.N
NameError
Newline character
"\n" in a Python string, marks a line break; a file’s last line may have no line ending."\n" adds another newline unless the print ending is changed.P
Parent directory
parent property selects that enclosing location.Path("reports/2026/sales.csv"), the parent is the path reports/2026.Parent exception class
Path
data/notes.txt names a text file inside the data folder under the current working directory.Path object
Path("data") / "scores.txt" builds a location that open() can accept directly.PermissionError
Physical line number
line_num identifies the ending line consumed for a record that spans two lines.Propagation
Q
Quoting
"River, West", while a plain comma split would break that name.R
raise statement
raise ValueError("amount must be positive") before calculating.Raw string
r prefix so backslashes are kept as literal characters instead of being interpreted as ordinary escapes.r"C:\new\table.txt" preserves the separators that would otherwise begin newline and tab escapes.Re-raising
raise, allowing local action without treating the failure as resolved.Record
Record ending
"\r\n".newline="" lets the writer supply its own endings without a second translation layer.Relative path
project/scripts makes ../data/notes.txt point into the neighboring project data folder.Row-level recovery
S
Specific handler
Stem
Path("logs/run.txt"), the stem is "run", while the full final name is "run.txt".Suffix
suffix property.Path("data/sales.csv") is ".csv", which a program can use when selecting table files.SystemExit
sys.exit() outside the ordinary Exception branch.sys.exit("Missing data") raises SystemExit with a message and failure status that an ordinary Exception handler misses.T
Text file
Traceback
Truncation
"w" destroys the old records even if the program never reaches a write call.try block
TypeError
"5" to 3 raises TypeError because string addition does not accept an integer as its second operand.U
UnicodeDecodeError
encoding="utf-8".UTF-8
encoding="utf-8" when opening a text file saved as UTF-8 so its accented letters decode correctly.V
Validation
ValueError
"3.5" is an allowed input type for int(), but it is not an integer string and raises ValueError.W
Whitespace stripping
line.strip(), a line containing only spaces and a newline becomes an empty string.with statement
with block closes even when converting a line inside the block raises an error.writerow
writer.writerow(["Ana", 8.5]) for a two-field record, not one prejoined string.writerows
writerows() to save several records in one call.Z
ZeroDivisionError
About this lesson
Make your own Study Materials
Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.