Files and Exceptions in Python

Learn to make Python programs work with files and cope with errors. Read text files whole or line by line, write and append text safely with 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

  1. 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 contents
      Use 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 statement
      Use with open(...) as f: so that files are closed at the right moment, even when something goes wrong.
    • Write and add text to files
      Choose the right mode to create, overwrite or extend a file, and write text with write() and print() so that lines come out exactly as intended.
    • Search, count and filter lines in a file
      Process 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.
  2. 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 correctly
      Write 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 pathlib
      Use Path objects from the pathlib module to join, inspect and check paths, find files, create folders and read or write small files in one step.
  3. Use Python's csv module 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.reader
      Understand 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.writer
      Create 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 DictWriter
      Read each CSV row as a dictionary keyed by the header, filter and summarize rows by column name, and write dictionaries back to CSV.
  4. 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 traceback
      Know 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 except
      Write try and except blocks 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 functions
      Complete a try statement with else and finally, predict the order in which its blocks run, and decide in which function an exception should be handled.
    • Make file and data programs fail gracefully
      Combine 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.
  5. Use raise to 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 input
      Use the raise statement 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 exceptions
      Pass 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.

Python Exceptions and Files study guide

5 chapters

1

Read 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.

OperationResultUseful when
f.read()All remaining text as one stringYou need a small file as a whole
f.readline()The next line as a stringYou need one line now
f.readlines()All remaining lines as a listYou need to reuse the lines
for line in f:One line per passYou 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() or float() 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

  • with closes 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 try and except.

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
ModeExisting fileMissing file
"r"Opens for readingRaises FileNotFoundError
"w"Empties, then opens for writingCreates it
"a"Adds output at the endCreates it
"x"Raises FileExistsErrorCreates 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
TestWhat it asks
line.startswith("From:")Does the line begin with this text?
"ERROR" in lineDoes 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.
2

Find 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
KindExampleStarting point
Absolute, macOS or Linux/Users/maya/data/notes.txtThe root /
Absolute, WindowsC:/Users/Maya/data/notes.txtThe root of drive C
Relativedata/notes.txtCurrent 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

  • Path joins parts with / and works directly with open().
  • name, stem, suffix, and parent expose 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().parent for script-relative data.
  • Use glob() to find matches and mkdir() to create missing folders.
3

Read 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 to writerows().
  • The writer converts values and handles quoting; None becomes 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

  • DictReader consumes 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 None by default.
  • DictWriter needs fieldnames to set column order.
  • Missing output keys become empty fields; unexpected keys raise ValueError by default.
4

Handle 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
TypeTypical cause
ValueErrorint("3.5"): a string with an unacceptable value
TypeErrorlen(5): an operation on the wrong kind of object
ZeroDivisionErrorDividing by zero
IndexErrorReading a list position that does not exist
KeyErrorLooking up a missing dictionary key
NameErrorUsing an undefined name
AttributeErrorAsking 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:

  • OSError is the parent of common file-system errors, including FileNotFoundError and PermissionError.
  • LookupError is the parent of IndexError and KeyError.
  • ArithmeticError is the parent of ZeroDivisionError.
  • UnicodeDecodeError belongs under ValueError.

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.
  • ValueError concerns an unacceptable value; TypeError concerns 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 try code 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 err gives access to the message inside the handler.
  • Keep the try focused 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

  • else runs only after normal completion of the try body.
  • finally runs before control leaves, including on return or an unhandled exception.
  • An exception in else is outside the preceding handlers in that statement.
  • Avoid exits from finally that 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.
5

Raise 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
ProblemSuitable type
Correct kind of input, unacceptable valueValueError
Wrong kind of object for the operationTypeError

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 ValueError for an unacceptable value and TypeError for 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 raise in a handler passes on the current exception.
  • raise NewError(...) from err records 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

5 Walkthroughs

1

Turn a text file into a filtered report

13 steps
Read lines, choose file modes, and save selected records while keeping file lifetimes clear.
  1. 1
    IntroductionRead, 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 with close both files when processing ends.

  2. 2
    ExplanationA file supplies strings

    Suppose events.txt contains "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.

  3. 3
    ChallengeChoose 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. Calling read() or readlines() would load the remaining contents into memory.

  4. 4
    ExampleKeep 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 first can happen afterward while another f.readline() cannot.

  5. 5
    ChallengePredict cleanup after an error

    Inside that file block, suppose int("oops") raises ValueError. The surrounding code has no handler. Does the file remain open, and does with hide 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 except handler would be needed to recover.

  6. 6
    ExplanationChoose 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 handle FileExistsError. File creation still requires the containing folders to exist.

  7. 7
    ExampleWrite 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, while writelines() still expects supplied strings to contain any required endings.

  8. 8
    ChallengePredict two runs

    Starting with no file, a program runs twice. Each run opens "runs.txt" in append mode and calls f.write("OK"). What text is saved?

    ---reveal---

    The file contains "OKOK". Append mode keeps the first run, but neither the mode nor write() adds a newline. Writing "OK\n" instead would make one line per run. Opening in "w" would leave only the latest "OK".

  9. 9
    ExampleClean 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 line separately lets output preserve its spacing. Only the cleaned copy is used to identify the level.

  10. 10
    ChallengeCheck 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.

  11. 11
    ExampleAssemble 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.

  12. 12
    ChallengeDiagnose 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.

  13. 13
    RecapTrace 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.

2

Locate project data from any launch folder

9 steps
Trace relative paths, build script-relative paths, and prepare folders with pathlib.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionFind the starting folder
  2. 2
    ExampleTrace a launch
  3. 3
    ChallengeChange the launch folder
  4. 4
    TipInspect before changing the path
  5. 5
    ExampleBuild from the script
  6. 6
    ExplanationPrepare a destination
  7. 7
    ChallengeInspect a name and find matches
  8. 8
    ChallengeCheck a proposed fix
  9. 9
    RecapSeparate location from availability
3

Read a table and write a named-column report

13 steps
Parse quoted CSV, convert numeric fields, and export selected columns in a controlled order.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionPreserve the table’s structure
  2. 2
    ExampleRead one quoted record
  3. 3
    ExampleOpen and convert
  4. 4
    ChallengeRecognize a short row
  5. 5
    ExampleWrite values as fields
  6. 6
    ChallengeKeep one field together
  7. 7
    ExplanationUse the header as keys
  8. 8
    ExampleFilter by stock
  9. 9
    ChallengeDistinguish missing from empty
  10. 10
    ExampleExport selected columns
  11. 11
    ChallengeAppend a later batch
  12. 12
    TipMatch separators and encodings
  13. 13
    RecapCheck both structure and meaning
4

Follow an error from a bad row to a useful response

15 steps
Read a traceback, select handlers, and distinguish retrying a file from recovering inside a row loop.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionChoose what can recover
  2. 2
    ExampleStart with the exception type
  3. 3
    ChallengeRecognize a different failure
  4. 4
    ExampleCatch only the expected conversion
  5. 5
    ChallengeOrder related handlers
  6. 6
    ExplanationGive success and cleanup separate jobs
  7. 7
    ChallengeTrace an unmatched error
  8. 8
    ConnectionLet a caller decide
  9. 9
    ExampleKeep recovery inside the record loop
  10. 10
    ExampleFollow three records
  11. 11
    ChallengeChange the loop boundary
  12. 12
    TipName the location correctly
  13. 13
    ChallengeChoose a complete result
  14. 14
    ExampleStop with an error status
  15. 15
    RecapPut each response at the right level
5

Design a function’s error behavior

10 steps
Validate a request, raise useful errors, and preserve distinctions and causes for callers.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionGive failure a clear path
  2. 2
    ExampleReject invalid requests
  3. 3
    ChallengeTrace a failed assignment
  4. 4
    ExplanationMatch the type to the problem
  5. 5
    ExampleName a distinct shortage
  6. 6
    ChallengeKeep the specific response reachable
  7. 7
    ExampleReact and pass the error onward
  8. 8
    ExampleTranslate a lower-level failure
  9. 9
    ChallengeChoose the right relationship
  10. 10
    RecapKeep the error meaningful to the caller

Python Exceptions and Files practice questions

50 Practice Questions in 5 sets

Set 1: Reading files and tracing small programs10 Practice Questions

Question 1 of 10

A file contains "oak\npine". Immediately after opening it for reading, what does f.readline() return?
  1. "oak"
  2. ["oak\n", "pine"]
  3. "oak\n"
  4. "oak\npine"
Show answerHide answer
Answer: C
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)
  1. False
  2. True
  3. None
  4. text
Show answerHide answer
Answer: B
Leaving the 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

A program must add a run message to a log while keeping all earlier messages. What text-file mode should it use?
  1. "a"
  2. "w"
  3. "r"
  4. "x"
Show answerHide answer
Answer: A
Append mode, "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

A terminal works in /work/lab. It runs python tools/count.py, which opens "inputs/list.txt". What absolute location does that relative path request?
  1. /work/lab/tools/inputs/list.txt
  2. /work/inputs/list.txt
  3. /inputs/list.txt
  4. /work/lab/inputs/list.txt
Show answerHide answer
Answer: D
The relative path starts from /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

For p = Path("exports/week/report.csv"), what is p.stem?
  1. ".csv"
  2. "report"
  3. "report.csv"
  4. "exports/week"
Show answerHide answer
Answer: B
The stem is the final name with its last suffix removed, giving "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

Using the default csv.reader, what list is read from the record "River, West",6,8?
  1. ['River, West', '6', '8']
  2. ['River, West', 6, 8]
  3. ['\"River', ' West\"', '6', '8']
  4. ['River', 'West', '6', '8']
Show answerHide answer
Answer: A
The quoted comma is part of one field, so the reader returns three strings: the place name and two numeric texts. It does not convert the digits into numbers under its default settings. Splitting at every comma would incorrectly break the place name.

Question 7 of 10

What row does writer.writerow("Leo") produce with the default comma delimiter?
  1. Leo
  2. "Leo"
  3. L,e,o
  4. L e o
Show answerHide answer
Answer: C
A string is a sequence of characters, so 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

A CSV quantity field contains the string "many". What exception does int(row["quantity"]) raise?
  1. TypeError
  2. KeyError
  3. IndexError
  4. ValueError
Show answerHide answer
Answer: D
The lookup succeeds and supplies a string, but "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")
  1. "read", then "end"
  2. "bad text", then "end"
  3. "zero", then "end"
  4. "zero", then "read"
Show answerHide answer
Answer: C
The string "0" converts successfully, but division in the helper raises ZeroDivisionError. It propagates to the caller, skips the rest of that try body, and reaches the matching handler, which prints "zero". Execution then prints "end"; a valid numeric string does not trigger the conversion handler.

Question 10 of 10

A function accepts an integer page count but cannot process a count below 1. For input -2, what is a suitable exception and message?
  1. TypeError("pages must be positive, got -2")
  2. ValueError("pages must be positive, got -2")
  3. IndexError("pages must be positive, got -2")
  4. NameError("pages must be positive, got -2")
Show answerHide answer
Answer: B
The input is already an integer, so its type is acceptable, but its value violates the requirement. 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)
  1. 7
  2. 0
  3. None
  4. 14
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

Inside an except ValueError: block, what statement passes the same active exception on to the caller?
  1. return
  2. raise
  3. continue
  4. pass
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A log has lines "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?
  1. "ERROR" in line
  2. line.startswith("ERROR")
  3. line.split()[2] == "ERROR"
  4. line.split()[1] == "ERROR"
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A file contains "12\n15\n". What pair results from first = f.read() followed by second = f.read() on one freshly opened reader?
  1. first == "12\n15\n", second == ""
  2. first == "12\n", second == "15\n"
  3. first == "12\n15\n", second == first
  4. first == [12, 15], second == []
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

On Windows, why can the Python string literal "C:\new\tasks.txt" fail to identify the intended file?
  1. The drive name makes this a drive-relative path.
  2. Backslashes work only in relative path strings.
  3. The backslashes begin newline and tab escapes.
  4. An absolute path must start with a forward slash.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A file begins with 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?
  1. The reader treats numeric values as field names.
  2. The call consumed the first data record.
  3. The reader cannot use a lowercase header.
  4. The loop skips records without quoted names.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

The first line is label;count, but the default CSV reader returns ["label;count"]. What reader setting matches this file?
  1. skipinitialspace=True
  2. delimiter=","
  3. quoting=csv.QUOTE_ALL
  4. delimiter=";"
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")
  1. "success", then "closed"
  2. "zero", then "closed"
  3. "zero", then "success"
  4. "closed", then "zero"
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A complete grant-payment total is required. A CSV has one invalid amount among 200 records. Why is skipping it and displaying the rest as the complete total a poor recovery choice?
  1. The total omits a required payment without saying so.
  2. A conversion failure prevents reopening the file.
  3. Skipping changes all remaining payment amounts.
  4. A CSV cannot contain both valid and invalid rows.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A FileNotFoundError occurs in a try. The first handler is except OSError: print("file problem"), and the second is except FileNotFoundError: print("missing"). What prints?
  1. "missing"
  2. "file problem", then "missing"
  3. "file problem"
  4. No handler matches.
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)
  1. False
  2. True
  3. A NameError traceback.
  4. A FileNotFoundError traceback.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A new file is written with f.writelines(["red", "blue\n"]), then opened once more in append mode to write "green\n". What text does it contain?
  1. "redblue\ngreen\n"
  2. "red\nblue\ngreen\n"
  3. "green\n"
  4. "redbluegreen\n"
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

Folders results and results/daily are missing. What should run before writing Path("results/daily/run.txt").write_text("ok", encoding="utf-8")?
  1. Path("results/daily").mkdir(exist_ok=True)
  2. Path("results/daily/run.txt").mkdir(parents=True)
  3. Path("results/daily").exists()
  4. Path("results/daily").mkdir(parents=True, exist_ok=True)
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

An append program writes a header only when not p.exists(). The path exists but has zero bytes. What condition also gives this file its needed header?
  1. p.exists() and p.stat().st_size > 0
  2. not p.exists() and p.stat().st_size == 0
  3. not p.exists() or p.stat().st_size == 0
  4. p.exists()
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A default 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()?
  1. None; raises TypeError.
  2. ""; raises ValueError.
  3. "5"; returns 5.
  4. No key; raises KeyError.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

What exception does the dictionary lookup {"east": 4}["west"] raise?
  1. IndexError
  2. ValueError
  3. KeyError
  4. NameError
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()
  1. Receives None; "leaving" prints first.
  2. Receives 11; nothing prints.
  3. Receives "leaving"; 11 prints first.
  4. Receives 11; "leaving" prints first.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A CSV summary must report malformed numeric rows and continue to later records. Where should the conversion’s try/except ValueError go?
  1. Around the whole loop, outside its body.
  2. Inside the loop, around each row conversion.
  3. After the loop, around the final print.
  4. Only around the initial call to open().
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

Given class LimitError(ValueError): pass, a LimitError is raised. What happens if except ValueError: appears before except LimitError:?
  1. Neither clause matches the custom type.
  2. Only the ValueError handler runs.
  3. Both handlers run in the written order.
  4. Only the LimitError handler runs.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

After trimming and skipping blank lines, a parser sets 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]?
  1. len(parts) == 3
  2. line.endswith("\n")
  3. len(line) > 3
  4. " " in parts[0]
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

At end of file, what does f.readline() return?
  1. None
  2. "\n"
  3. []
  4. ""
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?
  1. Read mode removes the final newline before writing.
  2. The first handle automatically becomes an append handle.
  3. The write opening empties the file before reading begins.
  4. The write handle copies each line before replacing it.
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?
  1. A missing-file handler with a useful response.
  2. A second existence check that guarantees access.
  3. Write mode to recreate the expected input empty.
  4. A trim operation to remove the missing file name.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A script must read data/menu.txt next to its own location regardless of launch folder. What expression builds that path in the script?
  1. Path.cwd() / "data" / "menu.txt"
  2. Path(__file__).resolve().parent / "data" / "menu.txt"
  3. Path(__file__) / "data" / "menu.txt"
  4. Path("data") / "menu.txt"
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A UTF-8 CSV begins with a byte order mark. With encoding="utf-8", its first header key is "\ufeffcode". What opening change removes the marker while preserving UTF-8 text?
  1. Use encoding="utf-8-sig" for the file.
  2. Use newline="\n" instead of newline="".
  3. Use delimiter=";" instead of a comma.
  4. Use skipinitialspace=True for all fields.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A row is {"title": "Map", "stock": "4", "cost": "3.50"}. A default DictWriter has fieldnames=["title", "stock"]. What happens when it writes the whole row unchanged?
  1. It writes two fields and drops cost.
  2. It adds cost to the header automatically.
  3. It raises ValueError for the extra key.
  4. It writes cost as a third unnamed field.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

An input loop catches ValueError from int(text). That handler prints missing_name, which has never been defined. What happens to the new NameError?
  1. The same except ValueError retries it automatically.
  2. It changes into the original conversion error.
  3. The handler suppresses it and completes normally.
  4. It propagates unless an outer handler catches it.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

After a header, a CSV record begins with "North on physical line 2 and ends with Hall",7 on line 3. After reading it, what location does reader.line_num report?
  1. 1
  2. 3
  3. 2
  4. 7
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A helper prints "bad size" and returns None for a negative size. Its caller immediately multiplies the result by 4. Why would raising ValueError at validation improve this failure path?
  1. It returns a numeric default for later arithmetic.
  2. It guarantees the caller will retry the request.
  3. It signals the invalid size before later arithmetic fails.
  4. It reports a type-conversion error before validation.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

After catching a KeyError as err, a handler runs raise ValueError("missing unit column") from err. What does the caller receive, and what cause is preserved?
  1. A KeyError caused by the ValueError.
  2. A ValueError caused by the KeyError.
  3. A ValueError without an earlier cause.
  4. A normal return with both message strings.
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

A log has "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?
  1. 1
  2. 0
  3. 3
  4. 2
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A process starts in /srv/course, runs tools/read.py, and opens "../shared/items.txt". What path does it request?
  1. /srv/course/shared/items.txt
  2. /srv/shared/items.txt
  3. /srv/course/tools/shared/items.txt
  4. /shared/items.txt
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A default CSV writer receives ["Vale, East", None, 3]. What record is produced, ignoring its final line ending?
  1. Vale, East,None,3
  2. "Vale, East",,3
  3. "Vale, East",None,3
  4. Vale,East,,3
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A script divides 30 by the hard-coded number 5 when its intended count is 6. It prints 6.0 with no exception. What kind of problem is this?
  1. A syntax error caused by the divisor.
  2. A TypeError in numeric division.
  3. A logic error in the chosen count.
  4. A ZeroDivisionError in the total.
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")
  1. "bad input", then "cleanup"
  2. "ready" only
  3. "cleanup" only
  4. "ready", then "cleanup"
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A program enters 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?
  1. src closes; FileExistsError prevents the body.
  2. src stays open; the body runs without a destination.
  3. src closes; the body appends to the destination.
  4. src stays open; the body replaces the destination.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A parser must accept every string that int() accepts, including leading spaces and a sign. Why attempt int(text) in try instead of requiring text.isdigit() first?
  1. The operations accept different sets of strings.
  2. isdigit() converts signed strings into integers.
  3. int() accepts every string containing a digit.
  4. A try statement removes spaces from input.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A tool runs sys.exit("Required file unavailable") inside code covered by except Exception:. What happens?
  1. The handler receives ValueError and retries.
  2. The tool returns the message as a normal value.
  3. SystemExit bypasses the handler; exit status is 1.
  4. The handler receives SystemExit and continues.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A CSV summary initializes 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?
  1. total = 8, skipped = 1
  2. total = 13, skipped = 2
  3. total = 13, skipped = 1
  4. total = 8, skipped = 2
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

Given class ImportDataError(Exception): pass, a caller catches only ValueError. What happens when its helper raises ImportDataError?
  1. It propagates because its class is outside the ValueError branch.
  2. It is caught because ValueError also descends from Exception.
  3. It is caught if its message describes an unacceptable value.
  4. It becomes ValueError when the helper passes it to the caller.
Show answerHide answer

Save this lesson to see this answer.

Stuck on your own question? Homework Help

Key Terms

83 Key Terms, each with its definition

A

Absolute path
An absolute path specifies a location from a file-system root, such as / on Unix-like systems or a drive root on Windows.
The location /Users/maya/data/notes.txt does not depend on the current working directory.
Accumulator
An accumulator is a variable updated as a loop runs to build a result such as a total or count from the records processed.
The variable errors starts at 0 and increases by 1 whenever the loop finds an error-level record.
Append mode
Append mode opens a file so new output is added at its end while existing contents are kept; it creates a missing file.
Using "a" for run messages keeps previous runs, but the message still needs its own newline.
AttributeError
An AttributeError signals a request for an attribute or method that an object does not provide.
Calling "hi".push("!") raises AttributeError because a Python string has no method named push.

B

Binary mode
Binary mode reads and writes raw bytes instead of decoded strings and therefore does not take a text encoding argument.
A mode such as "rb" identifies byte input, while text input uses a mode such as "r".
Buffer
A buffer is a temporary area of memory that holds data during input or output, such as written text waiting to reach a file.
Closing an output file flushes its buffered text so the pending writes are passed to the file.
Byte order mark
A byte order mark is an initial encoding marker that some UTF-8 exports include and that can appear in the first field if retained.
Reading with encoding="utf-8-sig" removes the initial marker so the first header matches its intended name.

C

Caller
A caller is the code that invokes a function and receives its returned result or an exception the function leaves unhandled.
The caller can catch an invalid withdrawal and ask for a smaller amount without changing the calculation helper.
Closed file
A closed file is a file object whose underlying file access has ended, so further reading or writing through it is unavailable.
After a 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
A context manager is an object that arranges entry and exit behavior around a with block, such as opening access and cleanup.
A file object acts as a context manager so a program can rely on automatic closure at the block’s exit.
CSV
CSV is a text format for table records made of separated fields, with quoting rules that allow separators and line breaks in values.
The record "Lopez, Maria",10,8 has three fields because its first comma is inside a quoted name.
CSV writer
A CSV writer serializes sequences of field values into records, converting values to text and applying the selected quoting rules.
A writer quotes a comma-containing product name automatically when the program supplies it as one field.
Current working directory
The current working directory is the process’s current folder, used as the starting location when Python interprets relative paths.
Running python tools/report.py from the project root does not by itself move into the tools folder.
Custom exception
A custom exception is a program-defined error class that lets callers recognize a particular problem separately from other failures.
An InsufficientFundsError can trigger a smaller-amount prompt while unrelated invalid values get another response.

D

Delegated handling
Delegated handling leaves an exception to a caller that has the context needed to choose a useful recovery action for the larger task.
A data helper reports failure, while the command-line part decides whether to retry, skip a file, or stop.
Delimiter
A delimiter is the character separating fields in a table format, such as a comma, semicolon, or tab chosen for a CSV reader.
A semicolon export needs delimiter=";" so a reader separates name;score into two fields.
DictReader
A DictReader reads CSV data records as dictionaries whose keys come from the header, while field values remain strings by default.
After the header name,score, a row can be accessed with row["score"] even if the columns are reordered.
DictWriter
A DictWriter writes dictionaries as CSV rows using a supplied field-name sequence to choose the columns and their order.
A writer with fieldnames=["product", "stock"] exports those columns when passed matching dictionaries.
Directory creation
Directory creation makes folders in the file system; mkdir(parents=True) can also make missing folders above the requested one.
Create output/daily before writing its report, since opening a new output file does not create folders.

E

else clause
An else clause on a try statement runs when the protected body completes normally, without an exception or an early control-flow exit.
A successful conversion can lead to output in else, while an error raised in that output is not caught by the earlier handlers.
Encoding
An encoding is a set of rules for representing characters as bytes, used when writing text and interpreting stored text.
The text "café" can become garbled if a reader uses an encoding different from the one used to save it.
Error message
An error message describes a failed operation or rejected value so the person reading it can understand what happened and what to fix.
The message "pages must be positive, got -2" is more useful than the single word "error".
Exception
An exception is an object that signals a failure and interrupts normal execution while Python searches for a matching handler.
A failed int("many") conversion raises an exception before the next statement in that block runs.
Exception binding
An exception binding names a caught error object through as so its type or message can be inspected within that handler.
In except ValueError as err:, printing err shows the message; the binding is deleted afterward.
Exception chaining
Exception chaining records an earlier error as the direct cause of a new exception through raise ... from err.
A missing price key can become a clearer row error while the traceback keeps the original KeyError as its cause.
Exception handler
An exception handler is an except block selected by a matching exception type to perform a controlled response to a failed operation.
A ValueError handler can explain that a quantity must be a whole number and let a surrounding loop ask again.
Exception hierarchy
An exception hierarchy is the parent-and-child structure of error classes that determines how handlers for broader types match.
A handler for OSError also matches FileNotFoundError, while a ValueError handler does not match KeyError.
Exclusive creation
Exclusive creation makes a new file only when the path is unused and raises FileExistsError if a file already exists there.
Mode "x" prevents a newly generated report from silently replacing a report at the same path.
Exit status
An exit status is a numeric result sent to the operating system when a program ends, allowing another program to detect failure.
sys.exit("Missing input") prints the message to error output and ends with exit status 1.
Extra field
An extra field is a record value beyond the header’s field count; a default DictReader collects such values under the key None.
With two header names, a three-value row keeps its named values and stores the extra value in a list.

F

Field
A field is one meaningful part of a record, separated or identified by a known format, such as a log level or a CSV quantity.
In a log with date, time, level, and message, checking the level avoids matching a word inside the message.
fieldnames
The fieldnames sequence gives the header names read by a DictReader or the expected output keys and order supplied to a DictWriter.
Calling writeheader() on a DictWriter prints the names in its configured fieldnames order.
File mode
A file mode is an argument to open() that selects permitted access and how opening treats existing contents at the path.
An activity log uses "a" to keep earlier messages, while a fresh report may use "w" to replace them.
File object
A file object is the object returned by open() that gives a program methods for reading or writing an opened file.
Inside with open("notes.txt", encoding="utf-8") as f:, the name f refers to the file object.
File position
A file position marks where the next reading operation begins and moves forward as the program consumes text from the file.
After f.read() has consumed the remaining contents, a second read returns an empty string.
FileExistsError
A FileExistsError signals an operation that requires an unused path when something already exists at that location.
Opening an existing report with mode "x" raises FileExistsError instead of replacing its contents.
FileNotFoundError
A FileNotFoundError signals that a requested file or directory cannot be found at the path used by a file-system operation.
A wrong launch folder can make a relative input path raise FileNotFoundError even when the file exists elsewhere.
finally clause
A finally clause runs cleanup as control leaves a try statement, including before a pending return or an unhandled exception continues.
A closing message in finally prints even when a conversion fails and no attached handler matches its type.

G

Glob pattern
A glob pattern selects paths by a name pattern, with a wildcard such as * 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
A graceful failure is a controlled response to a problem, giving useful information and continuing or stopping according to the task.
A missing report file leads to a clear request for a corrected path instead of a confusing crash for the user.

H

Header
A header is a row of column names that identifies the fields in a table, commonly placed before the data records in a CSV file.
The row product,stock,price names columns and should not be passed to integer conversion as data.

I

IndexError
An IndexError signals a sequence lookup at a position that does not exist, such as indexing beyond the end of a list.
A short CSV row with one field raises IndexError when positional code tries to access its second field.
IsADirectoryError
An IsADirectoryError signals an operation that expects a file but encounters a directory at the requested location.
On systems that distinguish this case, opening a folder as an ordinary input file raises IsADirectoryError.

K

KeyboardInterrupt
A KeyboardInterrupt signals a user interruption, commonly Ctrl+C, and belongs directly under BaseException instead of Exception.
A bare except: can catch Ctrl+C, while except Exception: leaves the interruption free to propagate.
KeyError
A KeyError signals a dictionary lookup for a key that is absent, including a CSV header name that does not match the requested key.
Looking up row["name"] fails when the table’s header created the key "Name" instead.

L

Line filter
A line filter selects records by a condition while reading a file, allowing the program to keep only the lines relevant to a task.
A log filter checks the level field and writes only records whose level equals "ERROR".
Logic error
A logic error makes a program produce the wrong result through incorrect reasoning or operations, without requiring an exception.
Dividing by the wrong nonzero count can produce a plausible average while the program runs to completion.

M

Missing field
A missing field is a value absent from a short CSV record; a default DictReader fills its known header key with None.
Under name,score, the row Ana has a missing score; Ana, instead contains an empty score string.

N

NameError
A NameError signals use of a name that has no available binding, often because it was misspelled or never assigned.
A handler that prints an undefined variable raises NameError while trying to report the original problem.
Newline character
A newline character, written "\n" in a Python string, marks a line break; a file’s last line may have no line ending.
Printing a line that already ends in "\n" adds another newline unless the print ending is changed.

P

Parent directory
A parent directory is the containing folder of a file or directory; a path’s parent property selects that enclosing location.
For Path("reports/2026/sales.csv"), the parent is the path reports/2026.
Parent exception class
A parent exception class is the class from which another error class derives, making its handlers match instances of that child type.
Deriving LimitError from ValueError allows an existing ValueError handler to catch it as well.
Path
A path describes a file or folder location through its names and separators, starting at a root or another known directory.
The path data/notes.txt names a text file inside the data folder under the current working directory.
Path object
A Path object represents a path in Python and provides operations to join components, inspect names, and access the file system.
The expression Path("data") / "scores.txt" builds a location that open() can accept directly.
PermissionError
A PermissionError signals that the operating system denies the access requested by a file-system operation.
An input file may exist but still raise PermissionError when the program does not have permission to read it.
Physical line number
A physical line number counts actual file lines, which can differ from CSV record counts when a quoted field contains a line break.
The reader’s line_num identifies the ending line consumed for a record that spans two lines.
Propagation
Propagation carries an unhandled exception outward through the calling functions until a matching handler is found or execution ends.
A file-reading helper can let FileNotFoundError reach the caller that knows whether to request another path.

Q

Quoting
Quoting surrounds a field with quote characters so a delimiter or line break within its value is kept as part of that field.
The reader keeps the comma inside "River, West", while a plain comma split would break that name.

R

raise statement
A raise statement explicitly signals an exception, interrupting the normal path and starting the search for a matching handler.
A function rejects a nonpositive amount with raise ValueError("amount must be positive") before calculating.
Raw string
A raw string uses an r prefix so backslashes are kept as literal characters instead of being interpreted as ordinary escapes.
The literal r"C:\new\table.txt" preserves the separators that would otherwise begin newline and tab escapes.
Re-raising
Re-raising sends the active caught exception onward with a bare raise, allowing local action without treating the failure as resolved.
A reader prints the missing path and then re-raises so its caller can decide whether to request another file.
Record
A record is one complete row of CSV fields; it usually occupies one physical line but can span lines through a quoted field.
A quoted address containing a line break remains one record when it is read by the CSV module.
Record ending
A record ending is the character sequence a CSV writer adds after a row; the default writer uses "\r\n".
Opening with newline="" lets the writer supply its own endings without a second translation layer.
Relative path
A relative path specifies a location from the process’s current working directory, so its meaning depends on that starting folder.
Starting in project/scripts makes ../data/notes.txt point into the neighboring project data folder.
Row-level recovery
Row-level recovery handles a record’s expected failure inside the processing loop, allowing later records to be considered when permitted.
A quick summary reports a bad quantity and increments a skipped count before reading the next CSV record.

S

Specific handler
A specific handler catches a narrow exception class, allowing expected problems to receive distinct messages without hiding every bug.
Place FileNotFoundError before OSError when a missing file needs a different response from other file problems.
Stem
A stem is the final component of a path with its last suffix removed, useful when deriving related output names from a file name.
For Path("logs/run.txt"), the stem is "run", while the full final name is "run.txt".
Suffix
A suffix is the final extension of a file name, including its leading period, and is available through a path’s suffix property.
The suffix of Path("data/sales.csv") is ".csv", which a program can use when selecting table files.
SystemExit
A SystemExit signals an intended process exit and is raised by sys.exit() outside the ordinary Exception branch.
Calling sys.exit("Missing data") raises SystemExit with a message and failure status that an ordinary Exception handler misses.

T

Text file
A text file stores characters as encoded bytes, commonly arranged in lines, and keeps its data after the writing program ends.
A program reads a saved list of scores from a text file at the start of the next run.
Traceback
A traceback reports the chain of calls leading to an unhandled exception and ends with the exception type and explanatory message.
The lowest call entry can identify division by an empty list’s length as the operation that failed.
Truncation
Truncation empties an existing file’s contents when it is opened in write mode, before any new text is supplied by the program.
Opening an input file with "w" destroys the old records even if the program never reaches a write call.
try block
A try block contains operations whose exceptions may be handled by the clauses attached to it, with remaining code skipped on failure.
An input conversion belongs in a small try block so a bad value can trigger a request for another input.
TypeError
A TypeError signals an operation applied to an unsuitable kind of object or an incompatible combination of object types.
Adding "5" to 3 raises TypeError because string addition does not accept an integer as its second operand.

U

UnicodeDecodeError
A UnicodeDecodeError signals that stored bytes cannot be decoded under the selected rules for interpreting text.
A text reader may raise UnicodeDecodeError when the actual file encoding does not match encoding="utf-8".
UTF-8
UTF-8 is a text encoding that can represent every Unicode character and uses a varying number of bytes per character.
Use encoding="utf-8" when opening a text file saved as UTF-8 so its accented letters decode correctly.

V

Validation
Validation checks whether input meets the requirements of an operation before the program uses it to produce a result.
A withdrawal function checks that the amount is positive and does not exceed the balance before subtracting.
ValueError
A ValueError signals that an operation received an allowed kind of object but a value it cannot interpret or accept for that task.
The string "3.5" is an allowed input type for int(), but it is not an integer string and raises ValueError.

W

Whitespace stripping
Whitespace stripping removes leading or trailing spacing characters from text, including spaces, tabs, and line endings.
After line.strip(), a line containing only spaces and a newline becomes an empty string.
with statement
A with statement enters a managed block and arranges cleanup when control leaves it; for an opened file, cleanup closes the file.
A file opened in a with block closes even when converting a line inside the block raises an error.
writerow
The writerow method writes one sequence of field values as a CSV record, including needed separators, quotes, and a record ending.
Use writer.writerow(["Ana", 8.5]) for a two-field record, not one prejoined string.
writerows
The writerows method writes a sequence of rows, treating each supplied row as a sequence of fields for one CSV record.
A list of name-and-score lists can be passed to writerows() to save several records in one call.

Z

ZeroDivisionError
A ZeroDivisionError signals division or a related arithmetic operation with a zero divisor, which prevents a numeric result.
An average calculation raises ZeroDivisionError if the list is empty and its length is used as the divisor.

About this lesson

By StudeliReport a mistake

Make your own Study Materials

Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.

Get Started