将python代码编译为PyCodeObject并编组为pyc文件

问题描述 投票:0回答:1

我尝试将python代码编译为PyCodeObject并编组为pyc文件。但是当我导入我的pyc文件时,它失败并且回溯是“ValueError:错误的编组数据(未知类型代码)”这是我的代码

import struct
import marshal
import time
import imp 
import sys 

def dump(co, filename):
    magic = imp.get_magic()
    time_string = struct.pack('L', int(time.time()))
    f = open("merge.pyc", "wb")
    f.write(magic)
    f.write(time_string)
    marshal.dump(dco, f)
    f.close()

demo = open("demo.py").read()
dco = compile(demo, "demo.py", "exec")
dump(dco, "dco.pyc")
python compilation marshalling
1个回答
0
投票

我想ValueError引发的是因为时间戳的类型不匹配。您应该确保fmt中的L参数(struct.pack使用,标准大小为4个字节)与python可执行文件具有相同的长度。

由于时间戳的值不会影响最终结果,因此在这里使类型合适就足够了。如果您使用64位版本的CPython,请尝试使用Q而不是L来确保8个字节。

===更新开始===

对不起,我在前面的描述中犯了一个严重的错误。

没有任何前缀的L意味着native,并且大小和字节顺序与机器的本机格式和字节顺序相同(在64位CPython中,它将是8个字节)。但是,写入pyc文件的时间戳在Python 2和3中始终为4个字节(小端)。

如果使用的是Python2,我们应该使用<L而不是L,它具有标准大小,4个字节。

如果使用的是Python3,除了timestamp之外,我们应该添加另外4个字节的字段source size,如下面的代码所示(importlib / _bootstrap_external.py,Python3.6.4)

def _code_to_bytecode(code, mtime=0, source_size=0):
    """Compile a code object into bytecode for writing out to a byte-compiled
    file."""
    data = bytearray(MAGIC_NUMBER)
    data.extend(_w_long(mtime))
    data.extend(_w_long(source_size))
    data.extend(marshal.dumps(code))
    return data

最后,您可以参考pkgutil.read_code(),这是编写代码的相反顺序。

===更新结束===

顺便说一下,你的代码中有一些缺陷:没有在co函数中使用filenamedump参数

© www.soinside.com 2019 - 2024. All rights reserved.