difflib — Helpers for computing deltas¶
Source code: Lib/difflib.py
This module provides classes and functions for comparing sequences. Most of them compare sequences of text lines (for example lists of strings, or file objects) and produce diffs – reports on the differences. Diffs can be produced in various formats, including HTML and context and unified diffs – formats produced by tools like diff and git diff.
Comparisons are done using a matching algorithm implemented in
SequenceMatcher – a flexible class for comparing pairs of sequences
of any type, not just text, so long as the sequence elements are
hashable.
Junk heuristic¶
difflib uses a junk heuristic: some items are deemed to be
junk, and ignored when searching for similarities.
Ideally, these are uninteresting or common items, such as blank lines
or whitespace.
This heuristic can speed the algorithm up (because it reduces the number of possible combinations) and it can produce results that are more understandable for humans (typically breaking on whitespace). But it can also cause pathological cases:
Inappropriately chosen junk items can cause an unexpectedly large (but still correct) result.
The default heuristic is asymmetric: only the second sequence is inspected when determining what is considered junk, so comparing A to B can give different results than comparing B to A and reversing the result.
By default, if the second input sequence is at least 200 items long, items that account for more than 1% it are considered junk.
Depending on your data, you should consider turning this heuristic off
(setting SequenceMatcher’s autojunk argument to False)
or tuning it (using the isjunk argument, perhaps to one of the
predefined functions).
The difflib algorithm¶
The algorithm used in SequenceMatcher predates, and is a little
fancier than, an algorithm published in the late 1980s by Ratcliff and
Obershelp under the hyperbolic name “gestalt pattern matching.”
The idea is to find the longest contiguous subsequence common to both inputs,
then recursively handle the pieces of the sequences to the left and to the
right of the matching subsequence.
See also
- Pattern Matching: The Gestalt Approach
Discussion of a similar algorithm by John W. Ratcliff and D. E. Metzener. This was published in Dr. Dobb’s Journal in July, 1988.
As an extension to the Ratcliff and Obershelp algorithm, difflib
searches for the longest junk-free contiguous subsequence.
See the Junk heuristic section for details.
CPython implementation detail: Timing
The basic Ratcliff-Obershelp algorithm is cubic time in the worst
case and quadratic time in the expected case.
difflib’s algorithm is quadratic time for the worst case and has
expected-case behavior dependent in a complicated way on how many elements
the sequences have in common;
best case time is linear.
Diff generation¶
- class difflib.Differ¶
This is a class for comparing sequences of lines of text, and producing human-readable differences or deltas. Differ uses
SequenceMatcherboth to compare sequences of lines, and to compare sequences of characters within similar (near-matching) lines.Each line of a
Differdelta 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
Lines beginning with ‘
?’ attempt to guide the eye to intraline differences, and were not present in either input sequence. These lines can be confusing if the sequences contain whitespace characters, such as spaces, tabs or line breaks.Note that
Differ-generated deltas make no claim to be minimal diffs. To the contrary, minimal diffs are often counter-intuitive for humans, because they synch up anywhere possible, sometimes at accidental matches 100 pages apart. Restricting synch points to contiguous matches preserves some notion of locality, at the occasional cost of producing a longer diff.The
Differclass has this constructor:- __init__(linejunk=None, charjunk=None, autojunk=True)¶
Optional keyword parameters linejunk and charjunk are for filter functions (or
None):linejunk: A function that accepts a single string argument, and returns true if the string is junk. The default is
None, meaning that no line is considered junk.charjunk: A function that accepts a single character argument (a string of length 1), and returns true if the character is junk. The default is
None, meaning that no character is considered junk.These junk-filtering functions speed up matching to find differences and do not cause any differing lines or characters to be ignored. Read the description of the
find_longest_match()method’s isjunk parameter for an explanation.Setting the optional autojunk argument to
Falsewill turn automatic junk heuristic off.Changed in version 3.16: Added keyword-only autojunk parameter.
Differobjects are used (deltas generated) via a single method:- compare(a, b)¶
Compare two sequences of lines, and generate the delta (a sequence of lines).
Each sequence must contain individual single-line strings ending with newlines. Such sequences can be obtained from the
readlines()method of file-like objects. The generated delta also consists of newline-terminated strings, ready to be printed as-is via thewritelines()method of a file-like object.
- class difflib.HtmlDiff¶
This class can be used to create an HTML table (or a complete HTML file containing the table) showing a side by side, line by line comparison of text with inter-line and intra-line change highlights. The table can be generated in either full or contextual difference mode.
Warning
The trailing newlines get stripped before the diff, so the result can be incomplete. See gh-71896 for details.
The constructor for this class is:
- __init__(tabsize=8, wrapcolumn=None, linejunk=None, charjunk=IS_CHARACTER_JUNK, *, autojunk=True)¶
Initializes instance of
HtmlDiff.tabsize is an optional keyword argument to specify tab stop spacing and defaults to
8.wrapcolumn is an optional keyword to specify column number where lines are broken and wrapped, defaults to
Nonewhere lines are not wrapped.linejunk and charjunk are optional keyword arguments passed into
ndiff()(used byHtmlDiffto generate the side by side HTML differences). Seendiff()documentation for argument default values and descriptions.Setting the optional autojunk argument to
Falsewill turn automatic junk heuristic off.Changed in version 3.16: Added keyword-only autojunk parameter.
The following methods are public:
- make_file(fromlines, tolines, fromdesc='', todesc='', context=False, numlines=5, *, charset='utf-8')¶
Compares fromlines and tolines (lists of strings) and returns a string which is a complete HTML file containing a table showing line by line differences with inter-line and intra-line changes highlighted.
fromdesc and todesc are optional keyword arguments to specify from/to file column header strings (both default to an empty string).
context and numlines are both optional keyword arguments. Set context to
Truewhen contextual differences are to be shown, else the default isFalseto show the full files. numlines defaults to5. When context isTruenumlines controls the number of context lines which surround the difference highlights. When context isFalsenumlines controls the number of lines which are shown before a difference highlight when using the “next” hyperlinks (setting to zero would cause the “next” hyperlinks to place the next difference highlight at the top of the browser without any leading context).Note
fromdesc and todesc are interpreted as unescaped HTML and should be properly escaped while receiving input from untrusted sources.
Changed in version 3.5: charset keyword-only argument was added. The default charset of HTML document changed from
'ISO-8859-1'to'utf-8'.
- make_table(fromlines, tolines, fromdesc='', todesc='', context=False, numlines=5)¶
Compares fromlines and tolines (lists of strings) and returns a string which is a complete HTML table showing line by line differences with inter-line and intra-line changes highlighted.
The arguments for this method are the same as those for the
make_file()method.
- difflib.context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n', *, autojunk=True)¶
Compare a and b (lists of strings); return a delta (a generator generating the delta lines) in context diff format.
Context diffs are a compact way of showing just the lines that have changed plus a few lines of context. The changes are shown in a before/after style. The number of context lines is set by n which defaults to three.
By default, the diff control lines (those with
***or---) are created with a trailing newline. This is helpful so that inputs created fromio.IOBase.readlines()result in diffs that are suitable for use withio.IOBase.writelines()since both the inputs and outputs have trailing newlines.For inputs that do not have trailing newlines, set the lineterm argument to
""so that the output will be uniformly newline free.The context diff format normally has a header for filenames and modification times. Any or all of these may be specified using strings for fromfile, tofile, fromfiledate, and tofiledate. The modification times are normally expressed in the ISO 8601 format. If not specified, the strings default to blanks.
>>> import sys >>> from difflib import * >>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n'] >>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n'] >>> sys.stdout.writelines(context_diff(s1, s2, fromfile='before.py',