【问题标题】:compare whether two python files result in same byte code (are code wise identical)比较两个 python 文件是否产生相同的字节码(代码相同)
【发布时间】:2021-02-10 11:09:55
【问题描述】:

我们正在进行一些代码清理。 清理只是关于格式化(如果有问题,那么我们甚至假设行号不会改变,但理想情况下我也想忽略行号的变化)

为了确保没有意外的代码更改,我想找到一种简单/快速的方法来比较两个源代码。

假设我有file1.pyfile2.py

有效的是使用 py_compile.compile(filename) 创建 .pyc 文件然后使用 uncompyle6 pycfile,然后剥掉cmets,对比一下结果, 但这太过分而且非常缓慢。

我想象的另一种方法是复制 file1.py 例如到file.py, 使用 py_compile.compile("file.py") 并保存 .pyc 文件

然后将file2.py 例如复制到file.py 并使用 使用 py_compile.compile("file.py") 并保存 .pyc 文件 最后比较两个生成的 .pyc 文件

这是否适用于所有(当前)版本 >= python 3.6

如果我记得至少对于 python2,pyc 文件可能包含时间戳或绝对路径,这可能会使比较失败。 (至少如果 pyc 文件的生成是在两台不同的机器上运行的)

有没有比较干净的方法来比较py2文件的字节码?

作为奖励功能(如果可能),我想为每个字节码创建一个哈希值,以便将来参考。

【问题讨论】:

    标签: python comparison bytecode pyc


    【解决方案1】:

    您可以尝试使用 Python 的内部 compile function,它可以从字符串编译(在您的情况下从文件读取)。例如,编译和比较来自两个等效程序和一个几乎等效程序的结果代码对象,然后仅出于演示目的(您想要做的事情)执行几个代码对象:

    import hashlib
    import marshal
    ​
    ​
    def compute_hash(code):
        code_bytes = marshal.dumps(code)
        code_hash = hashlib.sha1(code_bytes).hexdigest()
        return code_hash
    ​
    ​
    source1 = """x = 3
    y = 4
    z = x * y
    print(z)
    """
    source2 = "x=3;y=4;z=x*y;print(z)"
    ​
    source3 = "a=3;y=4;z=a*y;print(z)"
    ​
    obj1 = compile(source=source1, filename='<string>', mode='exec', dont_inherit=1)
    obj2 = compile(source=source2, filename='<string>', mode='exec', dont_inherit=1)
    obj3 = compile(source=source3, filename='<string>', mode='exec', dont_inherit=1)
    ​
    print(obj1 == obj2)
    print(obj1 == obj3)
    ​
    exec(obj1)
    exec(obj3)
    print(compute_hash(obj1))
    

    打印:

    True
    False
    12
    12
    48632a1b64357e9d09d19e765d3dc6863ee67ab9
    

    这将使您不必复制 py 文件、创建 pyc 文件、比较 pyc 文件等。

    注意:

    compute_hash 函数用于如果您需要一个可重复的哈希函数,即在连续程序运行中计算时,为同一代码对象重复返回相同的值。

    【讨论】:

    • 好主意。会试试这个。甚至没有想到编译的结果可能具有可比性。但是我担心obj1 的哈希值与obj2 的哈希值不同。它们是否产生相同的字节码,但我会检查编译是否正常。
    • 不能从同一台机器访问两个源?这将大大简化事情。但我认为如果你运行两个相同的 Python 解释器,即相同的确切版本,生成的代码将是相同的,因此两个哈希必须相同。
    • 我有多个用例。对于我现在尝试做的事情。同一台机器是完全可以接受的,但是哈希是随机的,并不能真正告诉您有关内容的信息,例如,尝试调用 python3 -c 'print(hash("hello new world"))' 两次。或者尝试打印对象的哈希值并更改对象的某些值并重新打印哈希值。
    • 那么哈希值保证是相同的,否则== 测试将在两个代码对象之间失败。
    • 但在代码对象的情况下,至少对于小例子来说,你是对的。两个代码对象的哈希值相同(如果在同一进程中执行)所以我不能存储它以供将来参考,但这对于我目前尝试做的事情没有问题
    【解决方案2】:

    可能不是你想要的答案 - 但你为什么不使用差异工具来比较文件是否被更改? https://linuxhandbook.com/diff-command/

    如果文件发生更改,请使用 meld 之类的合并工具来比较更改http://meldmerge.org/

    【讨论】:

    • diff 不能真正使用,因为以下行将产生相同的字节码。 a = "hello" vs. a = u"hello" vs. a = "hello" vs. a = "hello" #and a comment 这个想法是使代码更具可读性,更统一,以删除 python2 工件,例如 unicode strigns / 等的 u 前缀,但要确定不会意外替换错误的u",例如a = u"I can see u"m,它应该变成a = "i can see u",但不应该变成a = "i can see "
    • 我更改了问题标题以使我的意图(希望)更清晰
    猜你喜欢
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 2013-08-10
    • 1970-01-01
    • 2016-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多