python3: 从代码对象获取定义的函数?
python3: getting defined functions from a code object?
在python3中,我有以下代码:
path = '/path/to/file/containing/python/code'
source = open(path, 'r').read()
codeobject = compile(source, path, 'exec')
我已经检查了 codeobject
,但我没有找到任何方法来获取该对象中定义的所有函数的列表。
我知道我可以在 source
字符串中搜索以 def
开头的行,但如果可能的话,我想从代码对象中获取此信息。
我错过了什么?
一个代码对象是一个嵌套结构;函数在执行代码对象时创建,它们的主体作为常量的一部分作为单独的代码对象嵌入:
>>> example = '''\
... def foobar():
... print('Hello world!')
... '''
>>> codeobject = compile(example, '', 'exec')
>>> codeobject
<code object <module> at 0x11049ff60, file "", line 1>
>>> codeobject.co_consts
(<code object foobar at 0x11049fe40, file "", line 1>, 'foobar', None)
>>> codeobject.co_consts[0]
<code object foobar at 0x11049fe40, file "", line 1>
>>> codeobject.co_consts[0].co_name
'foobar'
反汇编顶级代码对象时,您可以看到函数对象是从这样的代码对象创建的:
>>> import dis
>>> dis.dis(codeobject)
1 0 LOAD_CONST 0 (<code object foobar at 0x11049fe40, file "", line 1>)
2 LOAD_CONST 1 ('foobar')
4 MAKE_FUNCTION 0
6 STORE_NAME 0 (foobar)
8 LOAD_CONST 2 (None)
10 RETURN_VALUE
前面的 MAKE_FUNCTION
opcode takes the code object from the stack, as well as the function name and any default argument values from the stack; you can see the LOAD_CONST
opcodes 将代码对象和名称放在那里。
然而,并非所有代码对象都是函数:
>>> compile('[i for i in range(10)]', '', 'exec').co_consts
(<code object <listcomp> at 0x1105cb030, file "", line 1>, '<listcomp>', 10, None)
>>> compile('class Foo: pass', '', 'exec').co_consts
(<code object Foo at 0x1105cb0c0, file "", line 1>, 'Foo', None)
如果您想列出字节码中加载了哪些函数,最好的办法是使用反汇编,而不是查找代码对象:
import dis
from itertools import islice
# old itertools example to create a sliding window over a generator
def window(seq, n=2):
"""Returns a sliding window (of width n) over data from the iterable
s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ...
"""
it = iter(seq)
result = tuple(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + (elem,)
yield result
def extract_functions(codeobject):
codetype = type(codeobject)
signature = ('LOAD_CONST', 'LOAD_CONST', 'MAKE_FUNCTION', 'STORE_NAME')
for op1, op2, op3, op4 in window(dis.get_instructions(codeobject), 4):
if (op1.opname, op2.opname, op3.opname, op4.opname) == signature:
# Function loaded
fname = op2.argval
assert isinstance(op1.argval, codetype)
yield fname, op1.argval
这会为给定代码对象中加载的所有函数生成 (name, codeobject)
元组。
在python3中,我有以下代码:
path = '/path/to/file/containing/python/code'
source = open(path, 'r').read()
codeobject = compile(source, path, 'exec')
我已经检查了 codeobject
,但我没有找到任何方法来获取该对象中定义的所有函数的列表。
我知道我可以在 source
字符串中搜索以 def
开头的行,但如果可能的话,我想从代码对象中获取此信息。
我错过了什么?
一个代码对象是一个嵌套结构;函数在执行代码对象时创建,它们的主体作为常量的一部分作为单独的代码对象嵌入:
>>> example = '''\
... def foobar():
... print('Hello world!')
... '''
>>> codeobject = compile(example, '', 'exec')
>>> codeobject
<code object <module> at 0x11049ff60, file "", line 1>
>>> codeobject.co_consts
(<code object foobar at 0x11049fe40, file "", line 1>, 'foobar', None)
>>> codeobject.co_consts[0]
<code object foobar at 0x11049fe40, file "", line 1>
>>> codeobject.co_consts[0].co_name
'foobar'
反汇编顶级代码对象时,您可以看到函数对象是从这样的代码对象创建的:
>>> import dis
>>> dis.dis(codeobject)
1 0 LOAD_CONST 0 (<code object foobar at 0x11049fe40, file "", line 1>)
2 LOAD_CONST 1 ('foobar')
4 MAKE_FUNCTION 0
6 STORE_NAME 0 (foobar)
8 LOAD_CONST 2 (None)
10 RETURN_VALUE
前面的 MAKE_FUNCTION
opcode takes the code object from the stack, as well as the function name and any default argument values from the stack; you can see the LOAD_CONST
opcodes 将代码对象和名称放在那里。
然而,并非所有代码对象都是函数:
>>> compile('[i for i in range(10)]', '', 'exec').co_consts
(<code object <listcomp> at 0x1105cb030, file "", line 1>, '<listcomp>', 10, None)
>>> compile('class Foo: pass', '', 'exec').co_consts
(<code object Foo at 0x1105cb0c0, file "", line 1>, 'Foo', None)
如果您想列出字节码中加载了哪些函数,最好的办法是使用反汇编,而不是查找代码对象:
import dis
from itertools import islice
# old itertools example to create a sliding window over a generator
def window(seq, n=2):
"""Returns a sliding window (of width n) over data from the iterable
s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ...
"""
it = iter(seq)
result = tuple(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + (elem,)
yield result
def extract_functions(codeobject):
codetype = type(codeobject)
signature = ('LOAD_CONST', 'LOAD_CONST', 'MAKE_FUNCTION', 'STORE_NAME')
for op1, op2, op3, op4 in window(dis.get_instructions(codeobject), 4):
if (op1.opname, op2.opname, op3.opname, op4.opname) == signature:
# Function loaded
fname = op2.argval
assert isinstance(op1.argval, codetype)
yield fname, op1.argval
这会为给定代码对象中加载的所有函数生成 (name, codeobject)
元组。