Read and write files safely with the with statement, understand file modes, and find files by pattern using the glob module.
Why: the with statement opens a file and guarantees it is closed afterward — even if an error happens. This pattern is called a context manager. Always use it for files.
with open('notes.txt', 'r') as file:
content = file.read() # whole file as one string
print(content)
# the file is automatically closed hereWhy: for big files, reading line by line uses far less memory than loading the whole thing. Looping over the file object hands you one line at a time.
with open('notes.txt', 'r') as file:
for line in file:
print(line.strip()) # strip() removes the trailing newlineWhy: the mode you pass to open() decides what you can do. "w" overwrites (or creates), "a" appends to the end, "r" reads. Use encoding="utf-8" so text with accents or emoji works everywhere.
with open('log.txt', 'w', encoding='utf-8') as file:
file.write('First line\n') # \n is a newline
file.write('Second line\n')
with open('log.txt', 'a', encoding='utf-8') as file:
file.write('Appended later\n')Note: "with" is not just for files. Any object that supports the context-manager protocol can clean itself up automatically — database connections, network sockets, and locks all use it. The rule of thumb: if something must be closed or released, look for a with-based way to use it.
# the same pattern, a different resource:
import threading
lock = threading.Lock()
with lock: # acquired here
# ... do work that must not run in two threads at once ...
pass
# lock is automatically released here, even if an error is raisedWhy: the glob module finds files whose names match a pattern. * matches anything; ** with recursive=True searches sub-folders too. Great for batch-processing a folder of files.
import glob
# every .txt file in the current folder
for path in glob.glob('*.txt'):
print(path)
# every .py file, including inside sub-folders
for path in glob.glob('**/*.py', recursive=True):
print(path)