Quiz: File Input and Output
Test your understanding before moving on. Target: 70% or higher to proceed confidently.
Section 1: Multiple Choice (1 point each)
1. What does the "r" mode do when passed to open()?
- A) Creates a new file for reading
- B) Opens an existing file for reading (error if file doesn't exist)
- C) Opens a file for reading, creating it if it doesn't exist
- D) Opens a file for both reading and writing
Answer
**B)** Opens an existing file for reading (error if file doesn't exist). *Why B:* Read mode requires the file to exist. If it doesn't, Python raises `FileNotFoundError`. *Why not A:* `"r"` does not create files — that's `"w"`, `"a"`, or `"x"`. *Why not C:* Only write and append modes create files automatically. *Why not D:* For both reading and writing, you'd need `"r+"`. *Reference:* Section 10.22. What happens to an existing file's content when you open it in "w" mode?
- A) The content is preserved, and new data is added at the end
- B) The content is preserved, and new data is added at the beginning
- C) The content is immediately erased, even before you write anything
- D) The content is backed up and then erased
Answer
**C)** The content is immediately erased, even before you write anything. *Why C:* Write mode truncates the file to zero length the moment `open()` is called. This is one of the most common sources of accidental data loss. *Why not A:* That describes append mode (`"a"`). *Why not B:* No standard mode inserts at the beginning. *Why not D:* Python does not create automatic backups. *Reference:* Section 10.43. Which of the following is the PRIMARY benefit of using with open(...) as f: instead of f = open(...)?
- A) It makes the code run faster
- B) It allows reading and writing simultaneously
- C) It guarantees the file is closed, even if an error occurs
- D) It automatically detects the file encoding
Answer
**C)** It guarantees the file is closed, even if an error occurs. *Why C:* The `with` statement uses a context manager that calls `f.close()` when the block exits, whether normally or due to an exception. *Why not A:* There is no performance difference. *Why not B:* The mode determines read/write access, not `with`. *Why not D:* Encoding must still be specified manually. *Reference:* Section 10.34. What does f.readlines() return?
- A) A single string containing the entire file
- B) A list of strings, one per line, with newline characters included
- C) A list of strings, one per line, with newline characters stripped
- D) A generator that yields one line at a time
Answer
**B)** A list of strings, one per line, with newline characters included. *Why B:* `readlines()` returns something like `["line 1\n", "line 2\n", "line 3\n"]`. The `\n` characters are part of the string. *Why not A:* That's what `read()` returns. *Why not C:* Newlines are preserved. You must call `.strip()` to remove them. *Why not D:* `readlines()` loads everything into memory at once. Iterating over the file object directly (`for line in f:`) is the lazy/generator-like approach. *Reference:* Section 10.25. Which pathlib operation joins path components in a cross-platform way?
- A)
Path("dir") + "file.txt" - B)
Path("dir") / "file.txt" - C)
Path("dir").join("file.txt") - D)
Path.concat("dir", "file.txt")
Answer
**B)** `Path("dir") / "file.txt"` *Why B:* The `/` operator is overloaded for `Path` objects. It joins components using the correct separator for the current operating system. *Why not A:* `+` on a `Path` object doesn't concatenate path components — it raises a `TypeError`. *Why not C:* `Path` has no `.join()` method (the `os.path.join()` function is the older approach). *Why not D:* There is no `Path.concat()` method. *Reference:* Section 10.66. When reading a CSV file in Python, why should you pass newline="" to open()?
- A) To make the file open faster
- B) To prevent Python's universal newline handling from interfering with the csv module
- C) To automatically strip newlines from each row
- D) To convert Windows line endings to Unix line endings
Answer
**B)** To prevent Python's universal newline handling from interfering with the csv module. *Why B:* The `csv` module has its own newline handling. If Python also translates newlines, the two systems can conflict, causing blank rows or corrupted data. *Why not A:* `newline=""` does not affect performance. *Why not C:* The csv module handles row parsing regardless. *Why not D:* That's what default newline handling does — but for CSV files, we want to disable it and let the csv module handle everything. *Reference:* Section 10.77. What is the difference between json.dump() and json.dumps()?
- A)
dump()is for dictionaries;dumps()is for lists - B)
dump()writes to a file object;dumps()returns a string - C)
dump()is faster;dumps()is safer - D)
dump()uses compact format;dumps()uses pretty format
Answer
**B)** `dump()` writes to a file object; `dumps()` returns a string. *Why B:* The "s" in `dumps` stands for "string." `json.dump(obj, file)` writes directly to a file. `json.dumps(obj)` returns a JSON-formatted string. *Why not A:* Both work with any JSON-serializable Python object. *Why not C:* Both are equally safe and perform similarly. *Why not D:* Both support the `indent` parameter for pretty printing. *Reference:* Section 10.88. What Python type does None become when serialized to JSON and then deserialized back?
- A) The string
"None" - B) The integer
0 - C) Python
None - D) Python
False
Answer
**C)** Python `None`. *Why C:* Python `None` maps to JSON `null`, and JSON `null` maps back to Python `None`. The round-trip is faithful. *Why not A:* JSON `null` is not a string — it's a distinct value. *Why not B:* JSON `null` is not a number. *Why not D:* JSON has separate `null`, `false`, and `true` values. *Reference:* Section 10.8Section 2: True or False (1 point each)
9. write() automatically adds a newline at the end of the string you pass to it.
Answer
**False.** Unlike `print()`, `write()` does NOT add a newline. You must include `\n` explicitly. *Reference:* Section 10.410. Iterating over a file object with for line in f: loads the entire file into memory.
Answer
**False.** Iterating over a file object reads one line at a time. This is the memory-efficient approach for processing large files. *Reference:* Section 10.511. csv.DictReader requires you to manually specify the column names.
Answer
**False.** `DictReader` automatically uses the first row of the CSV as the column names (dictionary keys). You can override this, but it's not required. *Reference:* Section 10.712. Python tuples survive a JSON round-trip — if you dump a tuple and load it back, you get a tuple.
Answer
**False.** Python tuples are converted to JSON arrays, which are loaded back as Python lists. The tuple-vs-list distinction is lost during JSON serialization. *Reference:* Section 10.8Section 3: Short Answer (2 points each)
13. You run this code and get an error:
with open("data/results.csv", "r") as f:
content = f.read()
Error: FileNotFoundError: [Errno 2] No such file or directory: 'data/results.csv'
List three possible causes and one debugging technique.
Answer
**Possible causes:** 1. The file doesn't exist at that path (typo in name or extension). 2. The current working directory is not what you expect — the relative path `data/results.csv` is relative to where the script is *run*, not where it *lives*. 3. The `data/` directory itself doesn't exist. **Debugging technique:** Print `Path.cwd()` to see the actual working directory, then compare it to where the file actually is. Alternatively, use `Path(__file__).parent / "data" / "results.csv"` for a path relative to the script's location. *Reference:* Section 10.914. Explain why this code is dangerous:
with open("important_data.txt", "w") as f:
pass
Answer
Opening a file in `"w"` (write) mode immediately truncates (erases) the file. Even though no `write()` call is made inside the block, the file's contents are already gone the moment `open()` executes. The file is now empty. This is dangerous because the data loss happens silently — there is no warning, confirmation, or undo. If `important_data.txt` contained years of data, it's now an empty file. *Reference:* Section 10.415. What is the output of this code?
with open("test.txt", "w") as f:
f.write("abc")
f.write("def")
with open("test.txt", "r") as f:
print(repr(f.read()))
Answer
'abcdef'
`write()` does not add newlines between calls. The two strings are concatenated directly. The file contains exactly six characters: `abcdef`.
*Reference:* Section 10.4
16. You have a CSV file with 10 million rows. Which approach is better and why?
# Approach A
with open("huge.csv", "r") as f:
reader = csv.reader(f)
data = list(reader) # load everything
# Approach B
with open("huge.csv", "r") as f:
reader = csv.reader(f)
for row in reader:
process(row)
Answer
**Approach B** is better. It processes one row at a time, keeping memory usage constant regardless of file size. Approach A loads all 10 million rows into a list, which could consume gigabytes of memory and potentially crash the program. The general rule: iterate over large files line by line (or row by row) rather than loading everything into memory at once. *Reference:* Section 10.5Section 4: Code Writing (3 points each)
17. Write a function copy_file(source: str, destination: str) -> None that copies the contents of one text file to another. Use with statements.
Answer
def copy_file(source: str, destination: str) -> None:
"""Copy the contents of source to destination."""
with open(source, "r") as src, open(destination, "w") as dst:
for line in src:
dst.write(line)
*Note:* Using line-by-line copying is memory-efficient. You could also use `dst.write(src.read())` for small files.
18. Write a function csv_average(filename: str, column: str) -> float that reads a CSV file and returns the average of the values in the specified column. Use csv.DictReader.
Answer
import csv
def csv_average(filename: str, column: str) -> float:
"""Return the average of a numeric column in a CSV file."""
total = 0.0
count = 0
with open(filename, "r", newline="") as f:
for row in csv.DictReader(f):
total += float(row[column])
count += 1
return total / count
19. Write a function save_high_scores(scores: list[dict], filename: str) -> None that saves a list of score dictionaries to JSON, and a companion load_high_scores(filename: str) -> list[dict] that loads them back. Each score dict has "player" and "score" keys. load_high_scores should return an empty list if the file doesn't exist.
Answer
import json
from pathlib import Path
def save_high_scores(scores: list[dict], filename: str) -> None:
"""Save high scores to a JSON file."""
with open(filename, "w") as f:
json.dump(scores, f, indent=2)
def load_high_scores(filename: str) -> list[dict]:
"""Load high scores from JSON. Returns [] if file missing."""
path = Path(filename)
if not path.exists():
return []
with open(path, "r") as f:
return json.load(f)
20. Write a program that reads sample-data.csv and produces a JSON file called employees.json where each employee is a dictionary with all their CSV fields plus a computed "weekly_pay" field. The JSON file should be an array of employee objects, pretty-printed.
Answer
import csv
import json
employees = []
with open("sample-data.csv", "r", newline="") as f:
for row in csv.DictReader(f):
row["weekly_pay"] = round(
float(row["hours_worked"]) * float(row["hourly_rate"]), 2
)
employees.append(row)
with open("employees.json", "w") as f:
json.dump(employees, f, indent=2)
print(f"Converted {len(employees)} employees to JSON.")