I also wanted to do this in Jython. But the method shown in the accepted answer does not work there, because co_consts not available for the code object. (Also, there seems to be no other way to request a code object to get the code objects of nested functions.)
But, of course, there are code objects somewhere, we have the initial and full access, so itโs just a matter of finding a simple path within a reasonable amount of time. So, here is one way that works. (Hold on to your seats.)
Suppose the mod module has the following code:
def outer(): def inner(): print "Inner"
First, get the external function code object directly:
code = mod.outer.__code__
In Jython, this is an instance of PyTableCode , and reading the source code, we find that the actual functions are implemented in a Java class made from your given script, which is referenced by object funcs code. (All of these scripted classes are subclasses of PyFunctionTable , which is why the declared type is funcs .) This is not visible from inside Jython, as a result of the magic mechanism, which is a design way to say that you are "addressing these things at your own risk.
So, we need to dive a little in Java. A class like this does the trick:
import java.lang.reflect.Field; public class Getter { public static Object getFuncs(Object o) throws NoSuchFieldException, IllegalAccessException { Field f = o.getClass().getDeclaredField("funcs"); f.setAccessible(true); return f.get(o); } }
Back to Jython:
>>> import Getter >>> funcs = Getter.getFuncs(mod.outer.__code__) >>> funcs mod$py@1bfa3a2
Now this funcs object has all the functions declared anywhere in the Jython script (those that are nested arbitrarily, inside classes, etc.). In addition, it has fields containing the corresponding code objects.
>>> fields = funcs.class.getDeclaredFields()
In my case, the code object corresponding to the nested function is the last one:
>>> flast = fields[-1] >>> flast static final org.python.core.PyCode mod$py.inner$24
To get the code object of interest:
>>> flast.setAccessible(True) >>> inner_code = flast.get(None)
And everything else matches the accepted answer, i.e. check out co_freevars , (which is in Jython, unlike co_consts ).
Itโs good that this approach is that you list exactly all the code objects that are declared anywhere in the source code file: functions, methods, generators, regardless of whether they are installed or not or something they are under something or under each other. They have nowhere else to hide.