I'm also still trying to figure out why many difflib functions return a generator instead of a list, what's the advantage there?

Well, think about it for a second - if you compare files, those files can in theory (and will be in practice) be quite large - returning the delta as a list, for exampe, means reading the complete data into memory, which is not a smart thing to do.

As for only returning the difference, well, there is another advantage in using a generator - just iterate over the delta and keep whatever lines you are interested in.

If you read the difflib documentation for Differ - style deltas, you will see a paragraph that reads:

Each line of a Differ delta begins with a two-letter code:
Code    Meaning
'- '    line unique to sequence 1
'+ '    line unique to sequence 2
'  '    line common to both sequences
'? '    line not present in either input sequence

So, if you only want differences, you can easily filter those out by using str.startswith

You can also use difflib.context_diff to obtain a compact delta which shows only the changes.

Answer from Jim Brissom on Stack Overflow
🌐
Python
docs.python.org › 3 › library › difflib.html
difflib — Helpers for computing deltas
""" Command-line interface to difflib.py providing diffs in four formats: * ndiff: lists every line and highlights interline changes. * context: highlights clusters of changes in a before/after format.
🌐
Beautiful Soup
tedboy.github.io › python_stdlib › generated › generated › difflib.ndiff.html
difflib.ndiff() — Python Standard Library
difflib.ndiff(a, b, linejunk=None, charjunk=<function IS_CHARACTER_JUNK>)[source]¶ · Compare a and b (lists of strings); return a Differ-style delta. Optional keyword parameters linejunk and charjunk are for filter functions (or None): linejunk: A function that should accept a single string argument, and return true iff the string is junk. The default is None, and is recommended; as of Python 2.3, an adaptive notion of “noise” lines is used that does a good job on its own.
🌐
Medium
medium.com › @zhangkd5 › a-tutorial-for-difflib-a-powerful-python-standard-library-to-compare-textual-sequences-096d52b4c843
A Tutorial of Difflib — A Powerful Python Standard Library to Compare Textual Sequences | by Kaidong Zhang | Medium
January 27, 2024 - Since difflib comes with the Python standard distribution, it supports almost all mainstream Python3 versions. Although this library may not be as famous as other third-party libraries (such as diff in git), difflib is a very useful and powerful tool when dealing with text comparison and merging.
🌐
W3Schools
w3schools.com › python › ref_module_difflib.asp
Python difflib Module
Python Examples Python Compiler Python Exercises Python Quiz Python Challenges Python Practice Problems Python Server Python Syllabus Python Study Plan Python Interview Q&A Python Bootcamp Python Training ... import difflib words = ["ape", "apple", "peach", "puppy"] print(difflib.get_close_matches("appel", words, n=1)) Try it Yourself »
Top answer
1 of 3
6

I'm also still trying to figure out why many difflib functions return a generator instead of a list, what's the advantage there?

Well, think about it for a second - if you compare files, those files can in theory (and will be in practice) be quite large - returning the delta as a list, for exampe, means reading the complete data into memory, which is not a smart thing to do.

As for only returning the difference, well, there is another advantage in using a generator - just iterate over the delta and keep whatever lines you are interested in.

If you read the difflib documentation for Differ - style deltas, you will see a paragraph that reads:

Each line of a Differ delta begins with a two-letter code:
Code    Meaning
'- '    line unique to sequence 1
'+ '    line unique to sequence 2
'  '    line common to both sequences
'? '    line not present in either input sequence

So, if you only want differences, you can easily filter those out by using str.startswith

You can also use difflib.context_diff to obtain a compact delta which shows only the changes.

2 of 3
4

Diffs must contain enough information to make it possible to patch a version into another, so yes, for your experiment of a single-line change to a very small document, storing the whole documents could be cheaper.

Library functions return iterators to make it easier on clients that are tight on memory or only need to look at part of the resulting sequence. It's ok in Python because every iterator can be converted to a list with a very short list(an_iterator) expression.

Most differencing is done on lines of text, but it is possible to go down to the char-by-char, and difflib does it. Take a look at the Differ class of object in difflib.

The examples all over the place use human-friendly output, but the diffs are managed internally in a much more compact, computer-friendly way. Also, diffs usually contain redundant information (like the text of a line to delete) to make patching and merging changes safe. The redundancy can be removed by your own code, if you feel comfortable with that.

I just read that difflib opts for least-surprise in favor of optimality, which is something I won't argue against. There are well known algorithms that are fast at producing a minimum set of changes.

I once coded a generic diffing engine along with one of the optimum algorithms in about 1250 lines of Java (JRCS). It works for any sequence of elements that can be compared for equality. If you want to build your own solution, I think that a translation/reimplementation of JRCS should take no more than 300 lines of Python.

Processing the output produced by difflib to make it more compact is also an option. This is an example from a small files with three changes (an addition, a change, and a deletion):

---  
+++  
@@ -7,0 +7,1 @@
+aaaaa
@@ -9,1 +10,1 @@
-c= 0
+c= 1
@@ -15,1 +16,0 @@
-    m = re.match(code_re, text)

What the patch says can be easily condensed to:

+7,1 
aaaaa
-9,1 
+10,1
c= 1
-15,1

For your own example the condensed output would be:

-8,1
+9,1
print "The end"

For safety, leaving in a leading marker ('>') for lines that must be inserted might be a good idea.

-8,1
+9,1
>print "The end"

Is that closer to what you need?

This is a simple function to do the compacting. You'll have to write your own code to apply the patch in that format, but it should be straightforward.

def compact_a_unidiff(s):
    s = [l for l in s if l[0] in ('+','@')]
    result = []
    for l in s:
        if l.startswith('++'):
            continue
        elif l.startswith('+'):
            result.append('>'+ l[1:])
        else:
            del_cmd, add_cmd = l[3:-3].split()
            del_pair, add_pair = (c.split(',') for c in (del_cmd,add_cmd))
            if del_pair[1]  != '0':
                result.append(del_cmd)
            if add_pair[1] != '0':
                result.append(add_cmd)
    return result
🌐
Real Python
realpython.com › ref › stdlib › difflib
difflib | Python Standard Library – Real Python
>>> import difflib >>> difflib.get_close_matches("pythn", ["python", "perl", "ruby"]) ['python'] Computes similarity ratios between any two sequences with SequenceMatcher · Generates unified diff output suitable for patch files with unified_diff() Produces human-readable line-by-line deltas with Differ and ndiff() Creates HTML tables for side-by-side comparison with HtmlDiff ·
🌐
Reddit
reddit.com › r/python › python difflib getting coherent data from ndiff instead of plain strings
r/Python on Reddit: Python difflib getting coherent data from ndiff instead of plain strings
January 15, 2018 - I am trying to use difflib.ndiff for this as I want the exact characters that were changed, and unified/context diff do not give such results, and html diff does not yeld results that cand be simply written to a log file.
🌐
GeeksforGeeks
geeksforgeeks.org › python › compare-sequences-in-python-using-dfflib-module
Compare sequences in Python using dfflib module - GeeksforGeeks
February 24, 2021 - Python3 · # import required module import difflib # assign parameters par1 = 'Geeks' par2 = 'geeks!' # compare parameters for ele in difflib.ndiff(par1, par2): print(ele) Output: - G + g e e k s + ! Example 2: Python3 ·
🌐
Parseltongue
parseltongue.co.in › exploring-the-difflib-module-in-python
ParselTongue - Exploring the difflib Module in Python
July 26, 2024 - import difflib text1 = """line 1 line 2 line 3 line 4""" text2 = """line 1 line 3 line 4 line 5""" text1_lines = text1.splitlines() text2_lines = text2.splitlines() diff = difflib.ndiff(text1_lines, text2_lines) print('\n'.join(diff)) Output · line 1 - line 2 line 3 line 4 + line 5 ·
Find elsewhere
🌐
Python
docs.python.org › zh-cn › 3 › library › difflib.html
difflib --- 计算差异的辅助工具 — Python 3.14.4 文档
""" Command-line interface to difflib.py providing diffs in four formats: * ndiff: lists every line and highlights interline changes. * context: highlights clusters of changes in a before/after format.
🌐
Python
docs.python.org › zh-cn › 3.13 › library › difflib.html
difflib --- 计算差异的辅助工具 — Python 3.13.14 文档
""" Command-line interface to difflib.py providing diffs in four formats: * ndiff: lists every line and highlights interline changes. * context: highlights clusters of changes in a before/after format.
🌐
Linux Hint
linuxhint.com › difflib-module-python
How to Use the Difflib Module in Python
August 11, 2021 - Linux Hint LLC, [email protected] 1210 Kelly Park Circle, Morgan Hill, CA 95037 Privacy Policy and Terms of Use
🌐
HotExamples
python.hotexamples.com › examples › difflib › - › ndiff › python-ndiff-function-examples.html
Python ndiff Examples, difflib.ndiff Python Examples - HotExamples
def code_diff_report(python_source, new_source, filename): line_commentary = [] line_changes = {} import difflib line_number = 1 for line in difflib.ndiff(python_source.split(u"\n"), new_source.split(u"\n")): state = line[0] line_text = line[2:].rstrip() if state == " ": line_number += 1 elif state == "+": if line_number in line_changes: line_change = line_changes[line_number] change_text = "Line {}: {} -> {}".format(line_number, line_change, line_text) line_commentary.append(change_text) del line_changes[line_number] else: change_text = "Line {}: {}".format(line_number, line_text) line_number += 1 elif state == "-": line_changes[line_number] = line_text elif state == "?": pass return "\n".join(line_commentary)
🌐
Python
docs.python.domainunion.de › 3 › library › difflib.html
difflib — Helpers for computing deltas — Python 3.14.6 documentation
""" Command-line interface to difflib.py providing diffs in four formats: * ndiff: lists every line and highlights interline changes. * context: highlights clusters of changes in a before/after format.
🌐
SourceForge
epydoc.sourceforge.net › stdlib › difflib-module.html
difflib
Function get_close_matches(word, ... two lists of strings, return a delta in context diff format. Function ndiff(a, b): Return a delta: the difference between `a` and `b` (lists of strings)....
🌐
Kyoto Suigakuin University
cc.kyoto-su.ac.jp › ~atsushi › Programs › VisualWorks › CSV2HTML › CSV2HTML_PyDoc › difflib.html
Python: module difflib
Function get_close_matches(word, ... two lists of strings, return a delta in context diff format. Function ndiff(a, b): Return a delta: the difference between `a` and `b` (lists of strings)....
🌐
Narkive
python-bugs-list.python.narkive.com › M011V57q › issue6931-awful-performance-in-difflib-ndiff-and-htmldiff
[issue6931] awful performance in difflib: ndiff and HtmlDiff
Permalink Tim Peters added the comment: I'm sympathetic, but I don't see a good solution here without using incompatible code. ndiff was built to generate "the highest quality diff possible", for text written and edited by humans, where "quality" is measured by human judgment (not an abstract ...
🌐
GitHub
github.com › python › cpython › blob › main › Lib › difflib.py
cpython/Lib/difflib.py at main · python/cpython
April 11, 2018 - · Function context_diff(a, b): For two lists of strings, return a delta in context diff format. · Function ndiff(a, b): Return a delta: the difference between `a` and `b` (lists of strings).
Author   python
🌐
Pretagteam
ww25.pretagteam.com › question › python-difflib-deltas-and-compare-ndiff
Pretagteam
October 16, 2021 - We cannot provide a description for this page right now
🌐
Py4u
py4u.net › discuss › 194147
Page not found
Page not found The page you're looking for is not found, please go to the main page · Popular Tutorials · Python Data Types · Comparison Operators · Lists In Python · Variable Assignments · Strings In Python · This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 ...