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_consts、co_names等),用types.CodeType来重新构造完整的code对象,单独的co_code是做不到的。验证网络节点运行同一程序:
如果你想确保每个节点运行的是同一程序,最可靠的方式是:- 把源码编译成同一个code对象(或者直接序列化源码)
- 对code对象(或序列化后的字节)计算哈希值(比如
hashlib.sha256(pickle.dumps(code_obj)).hexdigest()) - 每个节点对比这个哈希值,一致就说明程序相同。
当然你也可以把code对象转成十六进制字符串分发,每个节点还原后执行,本质和序列化是一样的。
通过类似exec的方式执行co_code:
不能直接exec(co_code),因为exec接受的是code对象、字符串或AST对象,而co_code是纯字节序列。必须先像前面那样构造出完整的code对象,再用exec()执行这个code对象。
内容的提问来源于stack exchange,提问作者Noah Bergh




