Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
246: The glob and fnmatch Modules
I've seen this pattern a dozen times in code reviews. A developer needs to process a few specific files in a folder, so they use os.listdir() and a simple if statement to filter them. It seems fine until the project grows and the file naming gets messy.
The "Contains" Trap
import os
# Goal: Process all JPEG images in the current directory
files = os.listdir('.')
images = [f for f in files if '.jpg' in f]
for img in images:
print(f"Processing image: {img}")
At first glance, this looks okay. But here is the bug: if you have a file named notes_about_jpg_compression.txt or a folder called jpg_backups, this code will try to "process" them as images. Using in is too blunt; it doesn't care where the string appears. You only want files that end with that extension, and you probably want to ignore case (so .JPG doesn't get skipped).
You could fix this with f.lower().endswith('.jpg'), but once you need more complex patterns—like "any file that starts with 'data', ends in '.csv', and has a date in the middle"—your if statements will become an unreadable mess of string slicing.
Finding Files with glob
This is where glob comes in. Instead of listing everything and filtering it yourself, glob lets you ask the filesystem for exactly what you want using Unix-style wildcards. The * character matches zero or more characters.
import glob
# This returns a list of paths that actually match the pattern
images = glob.glob('*.jpg')
# If you want to be case-insensitive on systems that care,
# or handle multiple extensions, you can use brackets:
images = glob.glob('*. [jJ][pP][gG]') # a bit clunky
# Or better yet, just run multiple globs or use fnmatch for the heavy lifting.
The biggest difference here is that glob returns the path to the file, not just the filename. If you search in 'logs/*.txt', you get 'logs/error.txt', which saves you from having to use os.path.join() later.
Precise Filtering with fnmatch
Sometimes you already have a list of filenames (maybe from a database or a different API) and you just need to check if they match a pattern without hitting the disk again. That's where fnmatch is your best friend. It provides the same wildcard logic as glob but works on strings.
import fnmatch
filenames = ['data_2023_01.csv', 'data_2023_02.csv', 'readme.txt', 'config.json']
# We only want the 2023 CSVs
csv_2023 = [f for f in filenames if fnmatch.fnmatch(f, 'data_2023_*.csv')]
print(csv_2023) # ['data_2023_01.csv', 'data_2023_02.csv']
I prefer fnmatch.fnmatch() because it's case-insensitive by default on Windows and case-sensitive on Linux (following the OS behavior). If you want to force a specific behavior regardless of the platform, use fnmatch.fnmatchcase().
Hunting through Subdirectories
One thing that trips people up is that glob.glob('*.txt') only looks in the current folder. If your project has a nested structure, you need the "recursive" flag. To make this work, you use the ** pattern, which means "this directory and all directories beneath it."
import glob
# Find every .py file in the project, no matter how deep it is
all_python_files = glob.glob('**/*.py', recursive=True)
Just a heads up: be careful with recursive=True in massive directory trees (like your entire home directory). It can take a long time to return because it's physically walking through every single folder on your drive.
📋 Practical Task
Log File Archive Filter
You are building a cleanup script for a server. The server generates logs with names like server_2023_01.log, server_2023_02.log, client_2023_01.log, and system_2022_12.log.
Write a Python script that does the following:
- Create a list of dummy filenames in a list variable (since you aren't interacting with a real filesystem for this exercise).
- Use the
fnmatchmodule to filter that list and find only the logs that belong to the year 2023 and start with eitherserverorclient. - Print the final filtered list.
Example Input: ['server_2023_01.log', 'client_2023_05.log', 'system_2023_01.log', 'server_2022_11.log', 'notes.txt']
Expected Output: ['server_2023_01.log', 'client_2023_05.log']
There are no comments for now.