Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the function for a compiled function object

A Python function has a code object __code__.

A sys.settrace trace frame has a f_code code object.

For those calls to the tracer that are functions, how can I get the function object (and its __annotation__ member)?

So far, by trial and error, I have:

if hasattr(frame.f_globals.get(frame.f_code.co_name),"__annotations__"):

This seems to work for functions, but not for class-member functions; worse, it confuses class-member functions with top-level functions of the same name.

(I'm on Python 3.2.3 (Xubuntu). I see that Python 3.3 inspect module has a signature function; will this return the annotation for a code object or does it too need a function object?)

like image 846
Will Avatar asked Oct 08 '12 18:10

Will


People also ask

How do I get the details of a function in Python?

Python help() function is used to get the documentation of specified module, class, function, variables etc. This method is generally used with python interpreter console to get details about python objects.

What is compile function in Python?

The compile() function returns the specified source as a code object, ready to be executed.

What is __ module __?

The __module__ property is intended for retrieving the module where the function was defined, either to read the source code or sometimes to re-import it in a script.

How do I see what methods are in a Python module?

You can use dir(module) to see all available methods/attributes.


2 Answers

Through the inspect.getframeinfo module. I mean -- there is no straightforward way of doing that in Python -- Most times you can get hold of the code object, without having the function already, it is through frame instrospection.

Inspect's getframeinfo function does return some information about the frame being run, then you can retrieve the function object by getting its name.

Tough this is implementation dependent and have some drawbacks:

>>> import inspect
>>> def a():
...   return inspect.currentframe()
... 

>>> inspect.getframeinfo(a())
Traceback(filename='<stdin>', lineno=2, function='a', code_context=None, index=None)
>>> b = inspect.getframeinfo(a())
>>> b.function
'a'

Another way, but still implementation dependent, is to use the gc module (garbage collector) to get referrers to said code object.

>>> import gc
>>> from types import FunctionType
>>> def a(): pass
... 
>>> code = a.__code__

>>> [obj for  obj in  gc.get_referrers(code) if isinstance(obj, FunctionType)  ][0]
<function a at 0x7f1ef4484500>
>>> 

-- This is for Python 3 - for Python 2 one should replace __code__ by func_code

like image 192
jsbueno Avatar answered Nov 15 '22 13:11

jsbueno


You can retrieve the function-object as an attribute of the module or the class:

import inspect
import sys


def frame_to_func(frame):
    func_name = frame.f_code.co_name
    if "self" in frame.f_locals:
        return getattr(frame.f_locals["self"].__class__, func_name)
    else:
        return getattr(inspect.getmodule(frame), func_name)


def tracefunc(frame, event, arg):
    if event in ['call', 'return']:
        func_obj = frame_to_func(frame)
        print(f"{event} {frame.f_code.co_name} {func_obj.__annotations__}")


def add(x: int, y: int) -> int:
    return x+y


if __name__ == '__main__':
    sys.settrace(tracefunc)
    add(1, 2)
    sys.settrace(None)

Output: call add {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}

The solution is inspired by this question.

like image 28
M. Gruber Avatar answered Nov 15 '22 15:11

M. Gruber