【发布时间】:2017-10-27 23:32:03
【问题描述】:
我有一个 python 脚本。
def hello(self):
return 6
print hello()
我在 CPython 中编译后反汇编
>>> c = compile(open('hello.py').read(), 'hello.py', 'exec')
>>> import dis
>>> dis.dis(c)
1 0 LOAD_CONST 0 (<code object hello at 0x1006c9230, file "hello.py", line 1>)
3 MAKE_FUNCTION 0
6 STORE_NAME 0 (hello)
3 9 LOAD_NAME 0 (hello)
12 CALL_FUNCTION 0
15 PRINT_ITEM
16 PRINT_NEWLINE
17 LOAD_CONST 1 (None)
20 RETURN_VALUE
我很好奇<code object hello at 0x1006c9230 ...> 是如何存储在 CPython 代码对象中的。有co_code 函数,但它只打印出字节码指令。如果我序列化我得到的 CPython 代码对象
>>> import marshal
>>> marshal.dumps(c)
'c\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00@\x00\x00\x00s\x15\x00\x00\x00d\x00\x00\x84\x00\x00Z\x00\x00e\x00\x00\x83\x00\x00GHd\x01\x00S(\x02\x00\x00\x00c\x01\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00C\x00\x00\x00s\n\x00\x00\x00d\x01\x00}\x01\x00|\x01\x00S(\x02\x00\x00\x00Ni\x06\x00\x00\x00(\x00\x00\x00\x00(\x02\x00\x00\x00t\x04\x00\x00\x00selft\x01\x00\x00\x00x(\x00\x00\x00\x00(\x00\x00\x00\x00s\x08\x00\x00\x00hello.pyt\x05\x00\x00\x00hello\x01\x00\x00\x00s\x04\x00\x00\x00\x00\x01\x06\x01N(\x01\x00\x00\x00R\x02\x00\x00\x00(\x00\x00\x00\x00(\x00\x00\x00\x00(\x00\x00\x00\x00s\x08\x00\x00\x00hello.pyt\x08\x00\x00\x00<module>\x01\x00\x00\x00s\x02\x00\x00\x00\t\x03'
我知道
def hello(self):
return 6
存储在转储中的某个位置,因为如果我将其更改为return 5,转储中的一个字节会从 6 切换到 5。
1) 有没有办法可以从 CPython 代码对象访问函数体。最接近我能得到它c.names 但这只会打印出一个字符串。我假设在幕后它是一个被序列化为字符串的 PyObject。我还想确认函数体确实存储在c.names。
2) marshal dump 将函数存储为字节码指令还是未编译的文字?当我搜索操作码 \x83 (RETURN_VALUE) 时,我倾向于未编译的文字,它只在转储中出现一次。我相信这意味着当应该有两个时只有一个 return 语句:一次退出函数 hello,一次返回 None 以退出脚本。
版本
Python 2.7.13+ (heads/2.7:96f5020597, May 26 2017, 15:26:13)
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
【问题讨论】:
-
这是很多问题。
-
“
<code object hello at 0x1006c9230 ...>”是什么意思?您的意思似乎与代码对象不同,除非您问的是代码对象如何存储代码对象的相当愚蠢的问题。 -
是的,我确实在问代码对象如何存储代码对象。出于某种原因,我从未想过要调查
co.co_consts。
标签: python c compiler-construction bytecode cpython