SequenceMatcher.get_grouped_opcodes() changes the result of later get_opcodes() calls

未关闭 适合新手
#161,973 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
78/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
python
领域
tooling

调研方向

从报告中提到的 SequenceMatcher.get_opcodes() 和 get_grouped_opcodes() 行为入手,使用 issue 中的复现代码比较分组前后的结果。完成标准是:调用 get_grouped_opcodes() 不再改变之后返回的完整 opcodes,并且使用更大的 n 分组时能保留预期的上下文。

由索引模型根据 Issue 内容生成。

描述

Bug report

SequenceMatcher.get_opcodes() caches its result and returns the same list on every call. get_grouped_opcodes() takes that list and overwrites its first and last entries to trim the context, so after one call the matcher's opcodes no longer cover the whole input, and a later get_grouped_opcodes() with a larger n shows less context than it should.

This was mentioned in gh-54194 back in 2010, but that issue was closed after only the get_matching_blocks() part was fixed (gh-65834); the get_grouped_opcodes() part is still there.

import difflib

old = ["line %d\n" % i for i in range(10)]
new = old[:]
new[5] = "changed\n"

sm = difflib.SequenceMatcher(None, old, new)
for group in sm.get_grouped_opcodes(1):
    pass  # show the hunks with one line of context
print(sm.get_opcodes())

Actual:

[('equal', 4, 5, 4, 5), ('replace', 5, 6, 5, 6), ('equal', 6, 7, 6, 7)]

Expected (what get_opcodes() returns before the get_grouped_opcodes() call):

[('equal', 0, 5, 0, 5), ('replace', 5, 6, 5, 6), ('equal', 6, 10, 6, 10)]

unified_diff() and context_diff() are not affected because they make a new matcher each time.

CPython versions tested on:

3.15, CPython main branch

Operating systems tested on:

Linux


Found while building a Lean 4 model of CPython (https://broyojo.com/python-formalization/). AI tools (Claude) helped investigate the findings and prepare this report. The examples were rerun on CPython 3.15.2 and main, and the report received technical review. Record: textlibs-difflib-grouped-opcodes-mutates-cache

主要语言
Python
星标
78.2k
派生
36.6k
平均合并
19 小时 57 分钟
30 天内合并 PR
630

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

python/cpython 的其他 Issue

查看 python/cpython 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。