You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在字节码层面对比两个Python脚本的结构?

利用Python字节码检测作业是否独立完成

作为教师,我时常难以判断学生的Python作业是否为独立完成。普通的文本对比只能检查变量、函数或类名,但这些名称不需要懂编码就能轻易修改,根本满足不了检测需求。我想知道能不能从字节码层面对比脚本的结构?比如下面这两个脚本:

学生作业示例

student_1.py

def my_add(a,b):
  return a+b

print(my_add(3,4))

student_2.py

def Add(x1,x2):
  return x1+x2

print(Add(4,3))

获取字节码的方法及输出

针对student_2.py的字节码获取代码

import dis

source = """
def Add(x1,x2):
  return x1+x2

print(Add(4,3))
"""

# 注:原代码中compile的第一个参数应为source变量,而非字符串'source',已修正
a = compile(source , '<string>' , 'exec')

print(dis.dis(source))

对应的字节码输出

0           0 RESUME                   0
2           2 LOAD_CONST               0 (<code object Add at 0x7fba144ebdf0, file "<dis>", line 2>)
4 MAKE_FUNCTION            0
6 STORE_NAME               0 (Add)
5           8 PUSH_NULL
10 LOAD_NAME                1 (print)
12 PUSH_NULL
14 LOAD_NAME                0 (Add)
16 LOAD_CONST               1 (4)
18 LOAD_CONST               2 (3)
20 PRECALL                  2
24 CALL                     2
34 PRECALL                  1
38 CALL                     1
48 POP_TOP
50 LOAD_CONST               3 (None)
52 RETURN_VALUE
Disassembly of <code object Add at 0x7fba144ebdf0, file "<dis>", line 2>:
2           0 RESUME                   0
3           2 LOAD_FAST                0 (x1)
4 LOAD_FAST                1 (x2)
6 BINARY_OP                0 (+)
10 RETURN_VALUE
None

针对student_1.py的字节码获取代码

import dis

source = """
def my_add(a,b):
  return a+b

print(my_add(3,4))
"""

# 同样修正compile参数问题
a = compile(source , '<string>' , 'exec')

print(dis.dis(source))

对应的字节码输出

0           0 RESUME                   0

  2           2 LOAD_CONST               0 (<code object my_add at 0x7f3ca44ebdf0, file "<dis>", line 2>)
4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (my_add)

  5           8 PUSH_NULL
             10 LOAD_NAME                1 (print)
             12 PUSH_NULL
             14 LOAD_NAME                0 (my_add)
             16 LOAD_CONST               1 (3)
             18 LOAD_CONST               2 (4)
             20 PRECALL                  2
             24 CALL                     2
             34 PRECALL                  1
             38 CALL                     1
             48 POP_TOP
             50 LOAD_CONST               3 (None)
             52 RETURN_VALUE

Disassembly of <code object my_add at 0x7f3ca44ebdf0, file "<dis>", line 2>:
  2           0 RESUME                   0

  3           2 LOAD_FAST                0 (a)
              4 LOAD_FAST                1 (b)
              6 BINARY_OP                0 (+)
             10 RETURN_VALUE
None

字节码层面的对比分析

对比两个脚本的字节码可以发现:

  • 函数内部的指令序列完全一致:都是RESUME 0 → LOAD_FAST 0 → LOAD_FAST 1 → BINARY_OP 0 (+) → RETURN_VALUE,只是参数名(x1/x2 vs a/b)对应的符号名不同,但指令逻辑完全一样。
  • 主程序的指令结构也高度相似:除了STORE_NAME的函数名(Add vs my_add)、LOAD_CONST的数值(4/3 vs 3/4)不同,其余指令的类型和执行顺序完全一致。

这说明两个脚本的核心逻辑完全相同,只是修改了函数名、参数名和调用参数的顺序,属于典型的抄袭行为。

内容的提问来源于stack exchange,提问作者Thomas K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 01:27:44