我知道我可以像这样从stdin运行python脚本:
python - < script.py
我也可以运行已编译的python文件:
python script.pyc
但是我无法从stdin运行编译的python文件:
python - < script.pyc
SyntaxError: Non-UTF-8 code starting with '\xee' in file <stdin> on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
显然我必须告诉解释器这是字节码。但是如何?
答案 0 :(得分:1)
TL/DR
这是可能的
cat script.pyc | python -c "import sys;import marshal;exec(marshal.loads(sys.stdin.buffer.read()[16:]))"
长版
上一个答案是错误的。可以通过 stdin 实现这一点。 Python 解释器有一个 -c 标志,允许它解释代码。 例如,
python -c "print('Hello, world!')"
将输出Hello, world!
可以使用内置库 sys
,特别是 sys.stdin.buffer.read()
函数在 Python 程序中读取标准输入。但是,这只能读取一次,并返回一个类似字节的对象。
.pyc
文件具有特殊的结构 - 4 个魔术字节、一个时间戳和一个编组的代码对象。
魔术字节和时间戳总共是 16 个字节。根据我的发现,时间戳无关紧要,但不同版本之间的魔术字节会发生变化。去掉这个,我们有一个编组的代码对象。这就是 [16:]
所做的 - 从标准输入中的类字节对象中删除魔术字节和时间戳。
Python 使用 marshal
库来压缩编译产生的代码对象,并提供 marshal.loads(bytes)
函数将类似字节的对象转换为未编组的对象,在这种情况下是一个实例types.CodeType
- 代码对象。
最后,虽然 Python 的 exec()
函数通常接受一个字符串,但它也可以接受一个代码对象。我们将代码对象传递给它,然后它执行它。
警告: 将字节码直接传递给标准输入然后执行是一个巨大的安全问题和糟糕的做法,但考虑到您首先尝试这样做,您可能不在乎。
参考:
sys — System-specific parameters and functions — Python 3.9.6 documentation
The structure of .pyc files | Ned Batchelder
Built-in Types — Python 3.9.6 documentation
marshal — Internal Python object serialization — Python 3.9.6 documentation
答案 1 :(得分:0)
字节码不应作为标准输入传递。它包含只能由pyhon解释器运行的可执行代码,在它之外,它只是乱码。基本上,当您尝试将文件作为标准输入传递时,它将被视为文本,因此会出现错误。 .py文件采用文本格式,因此可以像文本一样安全地解析并正确执行。
从您的代码示例中我将假设您正在尝试从bash控制台(Linux中的行)运行该文件,所以确实是正确的方法:
python script.pyc
这也是你也尝试过的。