6.3. difflib
—计算增量的帮助者¶
源代码: Lib/difflib.py
此模块提供了用于比较序列的类和函数。它可以用于例如比较文件,并且可以产生各种格式的差异信息,包括HTML和上下文以及统一差异。用于比较目录和文件,另请参阅 filecmp
模块。
-
class
difflib.
SequenceMatcher
¶ 这是用于比较任何类型的序列对的灵活类,只要序列元素是 hashable。基本算法比20世纪80年代由Ratcliff和Obershelp在双曲线名称“格式模式匹配”下公布的算法早,并且是一个有点幸运的。这个想法是找到不包含“垃圾”元素的最长的连续匹配子序列;这些“垃圾”元素在某种意义上是不感兴趣的元素,例如空白行或空格。 (处理垃圾是Ratcliff和Obershelp算法的扩展。)然后,将相同的想法递归地应用于匹配子序列左侧和右侧的序列片段。这不产生最小的编辑序列,但往往产生“看起来正确”的人的匹配。
定时: 基本Ratcliff-Obershelp算法是最坏情况下的三次时间和预期情况下的二次时间。
SequenceMatcher
是最坏情况的二次时间,并且预期情况行为以复杂的方式依赖于序列具有多少元素;最佳情况下时间是线性的。自动垃圾启发式:
SequenceMatcher
支持将某些序列项自动处理为垃圾的启发式算法。启发式计算每个单个项目在序列中出现的次数。如果项目的重复项(在第一个项目之后)占序列的1%以上且序列长度至少为200个项目,则该项目被标记为“流行”,并被视为垃圾以用于序列匹配。在创建SequenceMatcher
时,可以通过将autojunk
参数设置为False
来关闭此启发式。3.2 新版功能: autojunk 参数。
-
class
difflib.
Differ
¶ 这是一个类,用于比较文本行的序列,并产生人类可读的差异或增量。 Differ使用
SequenceMatcher
来比较线的序列,并且比较类似(近匹配)线内的字符序列。Differ
增量的每一行以双字母代码开头:码
含义
'- '
行对序列1唯一
'+ '
行对序列2唯一
' '
两个序列共有的
'? '
线不存在于任一输入序列中
以“
?
”开头的行试图引导眼睛到内向差异,并且不存在于任一输入序列中。如果序列包含选项卡字符,这些行可能会混淆。
-
class
difflib.
HtmlDiff
¶ 此类可用于创建一个并排显示的HTML表(或包含表的完整HTML文件),逐行比较文本与行间变化和行内变化亮点。该表可以在完全或上下文差分模式下生成。
这个类的构造函数是:
-
__init__
(tabsize=8, wrapcolumn=None, linejunk=None, charjunk=IS_CHARACTER_JUNK)¶ 初始化
HtmlDiff
的实例。tabsize 是一个可选的关键字参数,用于指定制表符间距,默认为
8
。wrapcolumn 是一个可选的关键字,用于指定行号被折断和换行的列号,缺省为
None
,其中行不被换行。linejunk 和 charjunk 是传递到
ndiff()
的可选关键字参数(由HtmlDiff
用于生成并行HTML差异)。有关参数默认值和描述,请参阅ndiff()
文档。
以下方法是公共的:
-
make_file
(fromlines, tolines, fromdesc='', todesc='', context=False, numlines=5, *, charset='utf-8')¶ 比较 fromlines 和 tolines (字符串列表),并返回一个字符串,它是一个完整的HTML文件,包含一个表格,显示行间差异,突出显示行间和行内更改。
fromdesc 和 todesc 是可选的关键字参数,用于指定从/到文件列标题字符串(默认为空字符串)。
context 和 numlines 都是可选的关键字参数。当要显示上下文差异时,将 context 设置为
True
,否则默认值为False
以显示完整文件。 numlines 默认为5
。当 context 为True
时,numlines 控制包围差异亮点的上下文线的数量。当 context 是False
时,numlines 控制在使用“下一个”超链接时显示在差异突出显示之前的行数(设置为零会导致“下一个”超链接将下一个差异突出显示放在浏览器的顶部,而没有任何前导上下文)。在 3.5 版更改: 添加了仅 charset 关键字参数。 HTML文档的默认字符集从
'ISO-8859-1'
更改为'utf-8'
。
-
make_table
(fromlines, tolines, fromdesc='', todesc='', context=False, numlines=5)¶ 比较 fromlines 和 tolines (字符串列表),并返回一个字符串,它是一个完整的HTML表格,显示逐行间差异,突出显示行间和行内更改。
此方法的参数与
make_file()
方法的参数相同。
Tools/scripts/diff.py
是此类的命令行前端,并包含其使用的一个很好的例子。-
-
difflib.
context_diff
(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n')¶ 比较 a 和 b (字符串列表);在上下文差异格式中返回增量(生成增量线的 generator)。
上下文差异是一种紧凑的方式,只显示已更改的行和上下文的几行。更改以前/后样式显示。上下文线的数量由 n 设置,默认为三。
默认情况下,差异控制线(具有
***
或---
的线)使用拖尾换行符创建。这是有帮助的,使得从io.IOBase.readlines()
创建的输入导致适合与io.IOBase.writelines()
一起使用的差异,因为输入和输出都具有尾随换行。对于没有尾随换行符的输入,将 lineterm 参数设置为
""
,以便输出将一致地换行。上下文差异格式通常具有文件名和修改时间的头。可以使用 fromfile,tofile,fromfiledate 和 tofiledate 的字符串来指定这些中的任何一个或全部。修改时间通常以ISO 8601格式表示。如果未指定,则字符串默认为空格。
>>> 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', tofile='after.py')) *** before.py --- after.py *************** *** 1,4 **** ! bacon ! eggs ! ham guido --- 1,4 ---- ! python ! eggy ! hamster guido
有关更详细的示例,请参阅 到difflib的命令行界面。
-
difflib.
get_close_matches
(word, possibilities, n=3, cutoff=0.6)¶ 返回最好的“足够好”匹配的列表。 word 是需要紧密匹配的序列(通常是字符串),possibilities 是与 word 匹配的序列列表(通常是字符串列表)。
可选参数 n (默认
3
)是要返回的最大匹配数; n 必须大于0
。可选参数 cutoff (默认
0.6
)是范围[0,1]中的浮点。忽略至少与 word 类似的得分的可能性。在列表中返回可能性中最好的(不超过 n)匹配,按照相似性分数排序,最相似。
>>> get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy']) ['apple', 'ape'] >>> import keyword >>> get_close_matches('wheel', keyword.kwlist) ['while'] >>> get_close_matches('pineapple', keyword.kwlist) [] >>> get_close_matches('accept', keyword.kwlist) ['except']
-
difflib.
ndiff
(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK)¶ 比较 a 和 b (字符串列表);返回
Differ
样式增量(生成增量线的 generator)。可选的关键字参数 linejunk 和 charjunk 是过滤功能(或
None
):linejunk:接受单个字符串参数的函数,如果字符串是junk则返回true,否则返回false。默认值为
None
。还有一个模块级函数IS_LINE_JUNK()
,它过滤掉没有可见字符的行,但最多只有一个字符('#'
) - 然而,基础SequenceMatcher
类动态分析哪些行频繁构成噪声,这通常比使用此功能更好。charjunk:接受字符(长度为1的字符串)的函数,如果字符是垃圾则返回,否则返回false。默认是模块级函数
IS_CHARACTER_JUNK()
,它过滤掉空格字符(一个空白或制表符;包含换行符是个不错的主意!)。Tools/scripts/ndiff.py
是此函数的命令行前端。>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(keepends=True), ... 'ore\ntree\nemu\n'.splitlines(keepends=True)) >>> print(''.join(diff), end="") - one ? ^ + ore ? ^ - two - three ? - + tree + emu
-
difflib.
restore
(sequence, which)¶ 返回生成增量的两个序列之一。
给定由
Differ.compare()
或ndiff()
产生的 sequence,提取源自文件1或2(参数 which)的行,剥离行前缀。例:
>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(keepends=True), ... 'ore\ntree\nemu\n'.splitlines(keepends=True)) >>> diff = list(diff) # materialize the generated delta into a list >>> print(''.join(restore(diff, 1)), end="") one two three >>> print(''.join(restore(diff, 2)), end="") ore tree emu
-
difflib.
unified_diff
(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n')¶ 比较 a 和 b (字符串列表);以统一差异格式返回增量(生成增量线的 generator)。
统一差异是一种紧凑的方式,只显示已更改的行,以及几行上下文。更改以内联样式显示(而不是单独的前/后块)。上下文线的数量由 n 设置,默认为三。
默认情况下,差异控制线(具有
---
,+++
或@@
的线)使用拖尾换行符创建。这是有帮助的,使得从io.IOBase.readlines()
创建的输入导致适合与io.IOBase.writelines()
一起使用的差异,因为输入和输出都具有尾随换行。对于没有尾随换行符的输入,将 lineterm 参数设置为
""
,以便输出将一致地换行。上下文差异格式通常具有文件名和修改时间的头。可以使用 fromfile,tofile,fromfiledate 和 tofiledate 的字符串来指定这些中的任何一个或全部。修改时间通常以ISO 8601格式表示。如果未指定,则字符串默认为空格。
>>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n'] >>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n'] >>> sys.stdout.writelines(unified_diff(s1, s2, fromfile='before.py', tofile='after.py')) --- before.py +++ after.py @@ -1,4 +1,4 @@ -bacon -eggs -ham +python +eggy +hamster guido
有关更详细的示例,请参阅 到difflib的命令行界面。
-
difflib.
diff_bytes
(dfunc, a, b, fromfile=b'', tofile=b'', fromfiledate=b'', tofiledate=b'', n=3, lineterm=b'\n')¶ 使用 dfunc 比较 a 和 b (字节对象列表);以 dfunc 返回的格式产生一系列delta线(也是字节)。 dfunc 必须是可调用的,通常是
unified_diff()
或context_diff()
。允许您比较具有未知或不一致编码的数据。除 n 之外的所有输入必须是字节对象,而不是str。通过无损地将所有输入(除 n)转换为str,并调用
dfunc(a, b, fromfile, tofile, fromfiledate, tofiledate, n, lineterm)
来工作。 dfunc 的输出然后被转换回字节,因此您接收的三角线具有与 a 和 b 相同的未知/不一致的编码。3.5 新版功能.
-
difflib.
IS_LINE_JUNK
(line)¶ 对于可忽略的行返回true。如果 line 为空或包含单个
'#'
,则线 line 可忽略,否则不可忽略。在旧版本中用作ndiff()
中参数 linejunk 的默认值。
-
difflib.
IS_CHARACTER_JUNK
(ch)¶ 对可忽略的字符返回true。如果 ch 是空格或制表符,则字符 ch 可忽略,否则不可忽略。用作
ndiff()
中参数 charjunk 的默认值。
参见
- 模式匹配:Gestalt方法
讨论John W. Ratcliff和D. E. Metzener的类似算法。这是1988年7月在 Dr. Dobb’s Journal 发表的。
6.3.1. SequenceMatcher对象¶
SequenceMatcher
类有这个构造函数:
-
class
difflib.
SequenceMatcher
(isjunk=None, a='', b='', autojunk=True) 可选参数 isjunk 必须是
None
(默认值)或单参数函数,它接受一个序列元素,并且当且仅当元素为“junk”且应被忽略时返回true。传递None
给 isjunk 相当于传递lambda x: 0
;换句话说,没有元素被忽略。例如,传递:lambda x: x in " \t"
如果您将行作为字符序列进行比较,并且不希望同步到空白或硬标签。
可选参数 a 和 b 是要比较的序列;两者默认为空字符串。两个序列的元件必须是 hashable。
可选参数 autojunk 可用于禁用自动垃圾启发式算法。
3.2 新版功能: autojunk 参数。
SequenceMatcher对象获得三个数据属性:bjunk 是 b 的元素集合,其中 isjunk 是
True
; bpopular 是被启发式算法流行的非垃圾元素集合(如果它没有被禁用); b2j 是将 b 的剩余元素映射到它们发生的位置的列表的dict。当 b 用set_seqs()
或set_seq2()
复位时,所有三个复位。3.2 新版功能: bjunk 和 bpopular 属性。
SequenceMatcher
对象有以下方法:-
set_seqs
(a, b)¶ 设置要比较的两个序列。
SequenceMatcher
计算和缓存关于第二个序列的详细信息,所以如果你想比较一个序列和许多序列,使用set_seq2()
设置常用的序列一次,并重复调用set_seq1()
,每个其他序列一次。-
set_seq1
(a)¶ 设置要比较的第一个序列。要比较的第二个序列不更改。
-
set_seq2
(b)¶ 设置要比较的第二个序列。第一个要比较的序列不会改变。
-
find_longest_match
(alo, ahi, blo, bhi)¶ 在
a[alo:ahi]
和b[blo:bhi]
中查找最长匹配块。如果省略 isjunk 或
None
,则find_longest_match()
返回(i, j, k)
,使得a[i:i+k]
等于b[j:j+k]
,其中alo <= i <= i+k <= ahi
和blo <= j <= j+k <= bhi
。对于符合那些条件的所有(i', j', k')
,还满足附加条件k >= k'
,i <= i'
和i == i'
,j <= j'
。换句话说,在所有最大匹配块中,返回在 a 中最早开始的块,以及在 a 中最早开始的所有最大匹配块中返回在 b 中最早开始的块。>>> s = SequenceMatcher(None, " abcd", "abcd abcd") >>> s.find_longest_match(0, 5, 0, 9) Match(a=0, b=4, size=5)
如果提供了 isjunk,则首先如上确定最长匹配块,但是具有在块中不出现垃圾元素的附加限制。然后,通过在两侧匹配(仅)垃圾元素尽可能地扩展该块。所以结果块永远不匹配垃圾,除非相同的垃圾恰好与一个有趣的匹配相邻。
这里是和以前相同的例子,但考虑空白是垃圾。这防止
' abcd'
直接匹配第二序列的尾端处的' abcd'
。相反,只有'abcd'
可以匹配,并且匹配第二序列中最左侧的'abcd'
:>>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd") >>> s.find_longest_match(0, 5, 0, 9) Match(a=1, b=0, size=4)
如果没有块匹配,则返回
(alo, blo, 0)
。此方法返回 named tuple
Match(a, b, size)
。
-
get_matching_blocks
()¶ 描述匹配子序列的三元组的返回列表。每个三元组具有形式
(i, j, n)
,并且意味着a[i:i+n] == b[j:j+n]
。三元组在 i 和 j 中单调增加。最后一个三元组是一个虚拟,并且具有值
(len(a), len(b), 0)
。它是唯一与n == 0
的三元组。如果(i, j, n)
和(i', j', n')
是列表中的相邻三元组,并且第二个不是列表中的最后三元组,则i+n != i'
或j+n != j'
;换句话说,相邻三元组总是描述不相邻的相等块。>>> s = SequenceMatcher(None, "abxcd", "abcd") >>> s.get_matching_blocks() [Match(a=0, b=0, size=2), Match(a=3, b=2, size=2), Match(a=5, b=4, size=0)]
-
get_opcodes
()¶ 描述如何将 a 转换为 b 的5元组的返回列表。每个元组的形式是
(tag, i1, i2, j1, j2)
。第一元组具有i1 == j1 == 0
,并且剩余的元组具有等于来自先前元组的 i2 的 i1,同样地,j1 等于先前的 j2。tag 值是字符串,具有以下含义:
值
含义
'replace'
a[i1:i2]
应由b[j1:j2]
替代。'delete'
a[i1:i2]
应删除。注意在这种情况下j1 == j2
。'insert'
b[j1:j2]
应插入a[i1:i1]
。注意在这种情况下i1 == i2
。'equal'
a[i1:i2] == b[j1:j2]
(子序列相等)。例如:
>>> a = "qabxcd" >>> b = "abycdf" >>> s = SequenceMatcher(None, a, b) >>> for tag, i1, i2, j1, j2 in s.get_opcodes(): ... print('{:7} a[{}:{}] --> b[{}:{}] {!r:>8} --> {!r}'.format( ... tag, i1, i2, j1, j2, a[i1:i2], b[j1:j2])) delete a[0:1] --> b[0:0] 'q' --> '' equal a[1:3] --> b[0:2] 'ab' --> 'ab' replace a[3:4] --> b[2:3] 'x' --> 'y' equal a[4:6] --> b[3:5] 'cd' --> 'cd' insert a[6:6] --> b[5:6] '' --> 'f'
-
get_grouped_opcodes
(n=3)¶ 返回具有高达 n 上下文行的组的 generator。
从
get_opcodes()
返回的组开始,此方法分割较小的更改集群,并消除没有更改的中间范围。返回的组的格式与
get_opcodes()
相同。
-
ratio
()¶ 将范围[0,1]中的序列相似性的度量返回为浮点。
其中T是两个序列中元素的总数,M是匹配数,这是2.0 * M / T。注意,如果序列相同,这是
1.0
,如果它们没有共同点,则为0.0
。如果
get_matching_blocks()
或get_opcodes()
尚未被调用,这是很昂贵的,在这种情况下,您可能想先尝试quick_ratio()
或real_quick_ratio()
来获得上限。
-
由于不同的近似级别,返回匹配与总字符的比率的三种方法可以给出不同的结果,尽管 quick_ratio()
和 real_quick_ratio()
总是至少与 ratio()
一样大:
>>> s = SequenceMatcher(None, "abcd", "bcde")
>>> s.ratio()
0.75
>>> s.quick_ratio()
0.75
>>> s.real_quick_ratio()
1.0
6.3.2. SequenceMatcher示例¶
此示例比较两个字符串,将空格视为“junk”:
>>> s = SequenceMatcher(lambda x: x == " ",
... "private Thread currentThread;",
... "private volatile Thread currentThread;")
ratio()
返回[0,1]中的浮点,测量序列的相似性。作为经验法则,ratio()
值大于0.6意味着序列是接近匹配:
>>> print(round(s.ratio(), 3))
0.866
如果你只对序列匹配的地方感兴趣,get_matching_blocks()
是方便的:
>>> for block in s.get_matching_blocks():
... print("a[%d] and b[%d] match for %d elements" % block)
a[0] and b[0] match for 8 elements
a[8] and b[17] match for 21 elements
a[29] and b[38] match for 0 elements
注意,get_matching_blocks()
返回的最后一个元组总是一个虚拟的 (len(a), len(b), 0)
,这是最后一个元组元素(匹配的元素数量)为 0
的唯一情况。
如果你想知道如何将第一个序列改成第二个,使用 get_opcodes()
:
>>> for opcode in s.get_opcodes():
... print("%6s a[%d:%d] b[%d:%d]" % opcode)
equal a[0:8] b[0:8]
insert a[8:8] b[8:17]
equal a[8:29] b[17:38]
参见
本模块中的
get_close_matches()
函数显示了如何使用SequenceMatcher
上的简单代码构建来做有用的工作。简单版本控制配方 用于使用
SequenceMatcher
构建的小型应用程序。
6.3.3. 不同对象¶
请注意,Differ
- 生成的增量不声称是 最小 差异。相反,最小差异通常是反直觉的,因为它们在任何可能的地方同步,有时偶然匹配100页。将同步点限制为连续匹配保留了局部性的一些概念,偶尔产生较长差异的代价。
Differ
类有这个构造函数:
-
class
difflib.
Differ
(linejunk=None, charjunk=None) 可选的关键字参数 linejunk 和 charjunk 用于过滤器功能(或
None
):linejunk:接受单个字符串参数的函数,如果字符串是junk,则返回true。默认值为
None
,这意味着没有行被认为是垃圾。charjunk:接受单个字符参数(长度为1的字符串)的函数,如果字符是垃圾则返回true。默认值为
None
,这意味着没有字符被认为是垃圾。这些垃圾过滤功能加速匹配以发现差异,并且不会导致任何不同的行或字符被忽略。请阅读
find_longest_match()
方法的 isjunk 参数的说明。通过单个方法使用
Differ
对象(生成delta):-
compare
(a, b)¶ 比较两个序列的行,并生成增量(行序列)。
每个序列必须包含以换行符结尾的单个单行字符串。这样的序列可以从文件状对象的
readlines()
方法获得。生成的delta还包括以换行符结尾的字符串,可以通过文件状对象的writelines()
方法按原样打印。
-
6.3.4. 不同的例子¶
本示例比较两个文本。首先我们设置文本,以换行符结尾的单个单行字符串的序列(这样的序列也可以从文件状对象的 readlines()
方法获得):
>>> text1 = ''' 1. Beautiful is better than ugly.
... 2. Explicit is better than implicit.
... 3. Simple is better than complex.
... 4. Complex is better than complicated.
... '''.splitlines(keepends=True)
>>> len(text1)
4
>>> text1[0][-1]
'\n'
>>> text2 = ''' 1. Beautiful is better than ugly.
... 3. Simple is better than complex.
... 4. Complicated is better than complex.
... 5. Flat is better than nested.
... '''.splitlines(keepends=True)
接下来我们实例化一个不同的对象:
>>> d = Differ()
注意,当实例化 Differ
对象时,我们可以传递函数来过滤出行和字符“垃圾”。有关详细信息,请参阅 Differ()
构造函数。
最后,我们比较两者:
>>> result = list(d.compare(text1, text2))
result
是一个字符串列表,所以让我们打印出来:
>>> from pprint import pprint
>>> pprint(result)
[' 1. Beautiful is better than ugly.\n',
'- 2. Explicit is better than implicit.\n',
'- 3. Simple is better than complex.\n',
'+ 3. Simple is better than complex.\n',
'? ++\n',
'- 4. Complex is better than complicated.\n',
'? ^ ---- ^\n',
'+ 4. Complicated is better than complex.\n',
'? ++++ ^ ^\n',
'+ 5. Flat is better than nested.\n']
作为单个多行字符串,它看起来像这样:
>>> import sys
>>> sys.stdout.writelines(result)
1. Beautiful is better than ugly.
- 2. Explicit is better than implicit.
- 3. Simple is better than complex.
+ 3. Simple is better than complex.
? ++
- 4. Complex is better than complicated.
? ^ ---- ^
+ 4. Complicated is better than complex.
? ++++ ^ ^
+ 5. Flat is better than nested.
6.3.5. 到difflib的命令行界面¶
此示例显示如何使用difflib创建类似 diff
的实用程序。它也包含在Python源代码分发中,如 Tools/scripts/diff.py
。
#!/usr/bin/env python3
""" 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.
* unified: highlights clusters of changes in an inline format.
* html: generates side by side comparison with change highlights.
"""
import sys, os, difflib, argparse
from datetime import datetime, timezone
def file_mtime(path):
t = datetime.fromtimestamp(os.stat(path).st_mtime,
timezone.utc)
return t.astimezone().isoformat()
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-c', action='store_true', default=False,
help='Produce a context format diff (default)')
parser.add_argument('-u', action='store_true', default=False,
help='Produce a unified format diff')
parser.add_argument('-m', action='store_true', default=False,
help='Produce HTML side by side diff '
'(can use -c and -l in conjunction)')
parser.add_argument('-n', action='store_true', default=False,
help='Produce a ndiff format diff')
parser.add_argument('-l', '--lines', type=int, default=3,
help='Set number of context lines (default 3)')
parser.add_argument('fromfile')
parser.add_argument('tofile')
options = parser.parse_args()
n = options.lines
fromfile = options.fromfile
tofile = options.tofile
fromdate = file_mtime(fromfile)
todate = file_mtime(tofile)
with open(fromfile) as ff:
fromlines = ff.readlines()
with open(tofile) as tf:
tolines = tf.readlines()
if options.u:
diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)
elif options.n:
diff = difflib.ndiff(fromlines, tolines)
elif options.m:
diff = difflib.HtmlDiff().make_file(fromlines,tolines,fromfile,tofile,context=options.c,numlines=n)
else:
diff = difflib.context_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)
sys.stdout.writelines(diff)
if __name__ == '__main__':
main()