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
264: The difflib Module for Comparing Sequences
Imagine you've just handed a technical spec to a colleague for review. They send it back, but instead of just saying "I fixed some typos," they've given you a "redline" version. You know the drill: there are strikethroughs for things they deleted, underlines for things they added, and the rest of the text remains untouched. You don't have to re-read the whole document; you just scan for the markings to see exactly how the document evolved.
That's exactly what the difflib module does for your data. Whether you're comparing two versions of a configuration file, two lists of usernames, or two strings of code, difflib identifies the delta—the difference—between them. In Python, the "redlines" are represented by specific prefixes: - for things in the first sequence but not the second, + for things in the second but not the first, and a blank space for things that are identical in both.
Getting the "Redline" View with ndiff
When I need a quick, human-readable comparison of two pieces of text, I usually reach for ndiff. It treats the sequences as lists of strings (usually lines in a file) and tells you exactly what happened line-by-line.
import difflib
old_config = [
"timeout = 30",
"retry_limit = 3",
"log_level = DEBUG",
"enabled = True"
]
new_config = [
"timeout = 60",
"retry_limit = 3",
"log_level = INFO",
"enabled = True",
"cache_size = 512"
]
diff = difflib.ndiff(old_config, new_config)
print('\n'.join(diff))
If you run this, you'll see that timeout and log_level are marked with a - and then a +. That's difflib's way of saying "this line was replaced." The cache_size line just gets a + because it's entirely new. I find this far more useful than a simple == check, which just tells you "these aren't the same" without explaining why.
Measuring Similarity with SequenceMatcher
Sometimes you don't need a line-by-line breakdown; you just want to know "how close" two sequences are. This is where SequenceMatcher comes in. It calculates a ratio between 0 and 1. I've used this in the past to build basic "did you mean?" functionality for command-line tools when a user typos a command.
from difflib import SequenceMatcher
string_a = "The quick brown fox jumps over the lazy dog"
string_b = "The quick brown fox leapt over the lazy dog"
matcher = SequenceMatcher(None, string_a, string_b)
print(f"Similarity: {matcher.ratio():.2%}")
The None argument is for a "junk" function—you can actually tell Python to ignore things like spaces or tabs if they aren't important to your comparison. For most of your work, leaving it as None is perfectly fine.
Generating Git-Style Patches
If you've ever looked at a .patch file or a Git diff, you've seen "unified diffs." They're much more compact than ndiff because they omit the parts of the file that didn't change, showing only a few lines of context around the edits. In a massive 1,000-line file, you don't want to scroll through 990 unchanged lines just to find one typo fix.
import difflib
text1 = ["Line 1\n", "Line 2\n", "Line 3\n", "Line 4\n"]
text2 = ["Line 1\n", "Line 2 modified\n", "Line 3\n", "Line 5\n"]
# unified_diff returns a generator, so we cast it to a list or join it
result = difflib.unified_diff(text1, text2, fromfile='original.txt', tofile='modified.txt')
print(''.join(result))
Notice that I added \n to the strings. unified_diff expects the strings to include their newline characters to format the output correctly. If you're reading lines directly from a file using readlines(), you're already covered. If you're creating lists manually, don't forget those newlines, or the output will look like a jumbled mess.
📋 Practical Task
Build a Software Version Change Logger
You are tasked with creating a tool that compares two versions of a requirements.txt file (represented as lists of strings) and generates a summary of the changes. Your script should:
- Take two lists:
old_requirementsandnew_requirements. - Use
difflib.ndiffto find the differences. - Parse the results to print a user-friendly summary in the following format:
- "Added: [package_name]"
- "Removed: [package_name]"
- "Changed: [old_package] → [new_package]"
Starter Data:
old_requirements = ["flask==2.0.1", "requests==2.25.1", "numpy==1.20.0"]
new_requirements = ["flask==2.1.0", "requests==2.25.1", "pandas==1.3.0"]
Hint: When iterating through ndiff, remember that a "change" is usually represented by a line starting with - immediately followed by a line starting with +.
There are no comments for now.