"""把当前源码编译结果与最后一版正确源码的 .pyc 逐个 code 对象比对。 这是修复正确性的最终判据:注释吞掉语句、误拆行等问题都会在字节码上暴露。 行号允许不同(注释多一行少一行不影响语义),比对的是 co_code、常量与名字。 """ import marshal import os import types _HERE = os.path.dirname(os.path.abspath(__file__)) _ROOT = os.path.dirname(_HERE) def index_code(root, prefix=""): table = {} def walk(c, path): key = path suffix = 0 while key in table: suffix += 1 key = f"{path}#{suffix}" table[key] = c for const in c.co_consts: if isinstance(const, types.CodeType): walk(const, f"{path}/{const.co_name}") walk(root, prefix or root.co_name) return table def scalars(c): return tuple( x for x in c.co_consts if not isinstance(x, types.CodeType) ) def main(): source = open(os.path.join(_ROOT, "wechat_bot.py"), encoding="utf-8").read() current = compile(source, "wechat_bot.py", "exec") good = marshal.loads( open(os.path.join(_HERE, "wechat_bot.lastgood.pyc"), "rb").read()[16:] ) left = index_code(current) right = index_code(good) only_current = sorted(set(left) - set(right)) only_good = sorted(set(right) - set(left)) print(f"当前 code 对象 {len(left)} 个,正确版 {len(right)} 个") if only_good: print(f"缺失的 code 对象 {len(only_good)} 个(说明有语句被吞进注释):") for name in only_good[:20]: print(" ", name) if only_current: print(f"多出来的 code 对象 {len(only_current)} 个:") for name in only_current[:20]: print(" ", name) differing = [] for name in sorted(set(left) & set(right)): a, b = left[name], right[name] if a.co_code != b.co_code: differing.append((name, "字节码")) elif scalars(a) != scalars(b): differing.append((name, "常量")) elif a.co_names != b.co_names or a.co_varnames != b.co_varnames: differing.append((name, "名字表")) if differing: print(f"\n有差异的 code 对象 {len(differing)} 个:") for name, kind in differing[:25]: print(f" [{kind}] {name}") if kind == "常量": a, b = scalars(left[name]), scalars(right[name]) for x, y in zip(a, b): if x != y: print(f" 当前={x!r}") print(f" 应为={y!r}") break else: print("\n所有 code 对象逐字节一致:代码语义与最后一版正确源码完全相同。") if __name__ == "__main__": main()