You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python中co_code还原为可执行形式、程序与十六进制字符串互转及相关编译执行问题咨询

Python字节码与可执行代码转换相关问题解答

嘿,我来帮你拆解这些关于Python字节码的问题,都是挺有意思的底层细节:

1. 把compile生成的co_code还原为可执行形式,以及Python程序转十六进制再还原的方法

首先明确:compile()函数输出的是code对象,而co_code只是这个对象里的字节码序列(bytes类型)。单独的co_code没法直接变成可执行代码,因为code对象还包含很多其他关键信息——比如参数数量、常量池、变量名列表、栈大小等等。不过只要你能拿到原code对象的这些配套属性,就能重新构造出可执行的code对象。

具体步骤(含十六进制转换):

举个实际的例子,咱们把一段代码转成十六进制字符串,再还原执行:

import types

# 1. 先编译一段源码得到code对象
source_code = "print('Hello from recovered code!')"
original_code = compile(source_code, "<temp>", "exec")

# 2. 把co_code转成十六进制字符串
co_code_hex = original_code.co_code.hex()
print(f"co_code的十六进制形式:{co_code_hex}")

# 3. 从十六进制字符串还原co_code字节码
recovered_co_code = bytes.fromhex(co_code_hex)

# 4. 用原code对象的其他属性,构造新的可执行code对象
recovered_code = types.CodeType(
    original_code.co_argcount,
    original_code.co_posonlyargcount,
    original_code.co_kwonlyargcount,
    original_code.co_nlocals,
    original_code.co_stacksize,
    original_code.co_flags,
    recovered_co_code,
    original_code.co_consts,
    original_code.co_names,
    original_code.co_varnames,
    original_code.co_filename,
    original_code.co_name,
    original_code.co_qualname,
    original_code.co_firstlineno,
    original_code.co_lnotab,
    original_code.co_freevars,
    original_code.co_cellvars
)

# 5. 执行还原后的code对象
exec(recovered_code)

如果想直接把整个Python程序(对应的code对象)存成十六进制,更简单的方式是序列化整个code对象(比如用pickle)再转十六进制:

import pickle

# 序列化code对象并转十六进制
code_hex = pickle.dumps(original_code).hex()

# 还原并执行
recovered_code_from_pickle = pickle.loads(bytes.fromhex(code_hex))
exec(recovered_code_from_pickle)

2. 把co_code转回compile的输出结果,以及验证节点程序一致性、执行co_code的方法

  • 把co_code转回compile的输出(即code对象)
    其实就是刚才第一步里的构造过程——因为compile()的输出就是code对象,而co_code只是它的一部分。必须结合原code对象的其他属性(比如co_constsco_names等),用types.CodeType来重新构造完整的code对象,单独的co_code是做不到的。

  • 验证网络节点运行同一程序
    如果你想确保每个节点运行的是同一程序,最可靠的方式是:

    1. 把源码编译成同一个code对象(或者直接序列化源码)
    2. 对code对象(或序列化后的字节)计算哈希值(比如hashlib.sha256(pickle.dumps(code_obj)).hexdigest()
    3. 每个节点对比这个哈希值,一致就说明程序相同。
      当然你也可以把code对象转成十六进制字符串分发,每个节点还原后执行,本质和序列化是一样的。
  • 通过类似exec的方式执行co_code
    不能直接exec(co_code),因为exec接受的是code对象、字符串或AST对象,而co_code是纯字节序列。必须先像前面那样构造出完整的code对象,再用exec()执行这个code对象。

内容的提问来源于stack exchange,提问作者Noah Bergh

火山引擎 最新活动