Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x python3:从代码对象获取定义的函数?_Python 3.x_Introspection - Fatal编程技术网

Python 3.x python3:从代码对象获取定义的函数?

Python 3.x python3:从代码对象获取定义的函数?,python-3.x,introspection,Python 3.x,Introspection,在python3中,我有以下代码: path = '/path/to/file/containing/python/code' source = open(path, 'r').read() codeobject = compile(source, path, 'exec') 我已经检查了codeobject,但我看不到任何方法可以获得该对象中定义的所有函数的列表 我知道我可以在源字符串中搜索以def开头的行,但如果可能的话,我想从code对象中获取此信息 我缺少什么?代码对象是嵌套结构;函数

在python3中,我有以下代码:

path = '/path/to/file/containing/python/code'
source = open(path, 'r').read()
codeobject = compile(source, path, 'exec')
我已经检查了
codeobject
,但我看不到任何方法可以获得该对象中定义的所有函数的列表

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


我缺少什么?

代码对象是嵌套结构;函数是在执行代码对象时创建的,函数体作为独立的代码对象嵌入,这些代码对象是常量的一部分:

>>> 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
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

这将为在给定代码对象中加载的所有函数生成
(名称,codeobject)
元组。

我明白了。但并不是所有co_consts列表中的项都是代码对象。我不知道如何检查每个对象的类型,以确定它们是嵌套的代码对象还是其他对象<代码>如果类型(codeobject[0])是什么:???如果类型(codeobject[0])是代码:,我尝试了
,但失败了。@Hipman:
类型(codeobject)
为您提供了正确的类型。是的,但是我要将
类型(codeobject)
与什么进行比较?python类型的名称是什么<代码>类型(codeobject)是什么???在
if
语句中,我应该用什么替换“What”?@hipman:
if-isinstance(constant_-object,type(codeobject))
已经可以了。@hipman:通常不需要从Python代码创建代码对象,因此没有内置的直接引用类型,而是
type(codeobject)
让您可以访问它。那么您的目标是什么;要列出代码对象中该部分的所有函数名?或者提取这些函数的所有代码?
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