【问题标题】:python3: getting defined functions from a code object?python3:从代码对象中获取定义的函数?
【发布时间】:2017-09-02 18:01:46
【问题描述】:

在python3中,我有以下代码:

path = '/path/to/file/containing/python/code'
source = open(path, 'r').read()
codeobject = compile(source, path, 'exec')

我检查了codeobject,但我没有看到任何方法来获取该对象中定义的所有函数的列表。

我知道我可以在 source 字符串中搜索以 def 开头的行,但如果可能的话,我想从代码对象中获取此信息。

我错过了什么?

【问题讨论】:

  • 那么你的目标是什么?列出代码对象的那部分函数的所有名称?或者提取这些函数的所有代码?

标签: python-3.x introspection


【解决方案1】:

代码对象是一个嵌套结构; 在代码对象执行时创建函数,它们的主体嵌入为作为常量一部分的单独代码对象:

>>> 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 从堆栈中获取代码对象,以及从堆栈中获取函数名和任何默认参数值;您可以看到它前面的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) 元组。

【讨论】:

  • 我明白了。但并非 co_consts 列表中的所有项目都是代码对象。我不知道如何检查每个的类型以查看它们是嵌套代码对象还是其他东西。 if type(codeobject[0]) is WHAT:???我试过if type(codeobject[0]) is code:,但失败了。
  • @HippoMan: type(codeobject) 为您提供正确的类型。
  • 是的,但是我将type(codeobject) 与什么进行比较? python类型的名称是什么? type(codeobject) is WHAT???在if 语句中,我应该用什么替换“WHAT”?
  • @HippoMan: if isinstance(constant_object, type(codeobject)) 已经可以了。
  • @HippoMan:您通常不需要从 Python 代码创建代码对象,因此没有对类型的内置直接引用,但type(codeobject) 让您可以访问它。跨度>
猜你喜欢
  • 1970-01-01
  • 2014-01-22
  • 1970-01-01
  • 2011-03-05
  • 1970-01-01
  • 2019-10-01
  • 1970-01-01
  • 2012-01-10
  • 1970-01-01
相关资源
最近更新 更多