1

In python3, I have the following code:

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

I have examined codeobject, but I don't see any way to get a list of all the functions that are defined within that object.

I know I can search the source string for lines that begin with def, but I want to get this info from the code object, if at all possible.

What am I missing?

1
  • So what is your goal here; to list all the names of functions that part of the code object? Or to extract all code for those functions? Commented Sep 2, 2017 at 18:13

1 Answer 1

3

A code object is a nested structure; functions are created when the code object is executed, with their bodies embedded as separate code objects that are part of the constants:

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

When you disassemble the top-level code object you can see that the function objects are created from such code objects:

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

The 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 preceding it that put the code object and name there.

Not all code objects are functions however:

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

If you wanted to list what functions are loaded in the bytecode, your best bet is to use the disassembly, not look for code objects:

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

This generates (name, codeobject) tuples for all functions that are loaded in a given code object.

Sign up to request clarification or add additional context in comments.

9 Comments

I see. But not all of the items in the co_consts lists are code objects. I don't know how to check the type of each one to see whether they are nested code objects or something else. if type(codeobject[0]) is WHAT:??? I tried if type(codeobject[0]) is code:, but that failed.
@HippoMan: type(codeobject) gives you the right type.
Yes, but what do I compare type(codeobject) to? What is the name of the python type? type(codeobject) is WHAT??? What do I replace "WHAT" with in an if statement?
@HippoMan: if isinstance(constant_object, type(codeobject)) would do already.
@HippoMan: you don't normally need to create code objects from Python code, so there is no built-in direct reference to the type, but type(codeobject) gives you access to it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.