Question

Given the function

def f():
    x, y = 1, 2 
    def get():
        print 'get'
    def post():
        print 'post'

is there a way for me to access its local get() and post() functions in a way that I can call them? I'm looking for a function that will work like so with the function f() defined above:

>>> get, post = get_local_functions(f)
>>> get()
'get'

I can access the code objects for those local functions like so

import inspect
for c in f.func_code.co_consts:
    if inspect.iscode(c):
        print c.co_name, c

which results in

get <code object get at 0x26e78 ...>
post <code object post at 0x269f8 ...>

but I can't figure out how to get the actual callable function objects. Is that even possible?

Thanks for your help,

Will.

Was it helpful?

Solution

You are pretty close of doing that - just missing new module:

import inspect
import new

def f():
    x, y = 1, 2
    def get():
        print 'get'
    def post():
        print 'post'

for c in f.func_code.co_consts:
    if inspect.iscode(c):
        f = new.function(c, globals())
        print f # Here you have your function :].

But why the heck bother? Isn't it easier to use class? Instantiation looks like a function call anyway.

OTHER TIPS

You can return functions just like any other object in Python:

def f():
    x, y = 1, 2 
    def get():
        print 'get'
    def post():
        print 'post'
    return (get, post)


get, post = f()

Hope this helps!

Note, though, that if you want to use your 'x' and 'y' variables in get() or post(), you should make them a list.

If you do something like this:

def f():
    x = [1]
    def get():
        print 'get', x[0]
        x[0] -= 1
    def post():
        print 'post', x[0]
        x[0] += 1
    return (get, post)

get1, post1 = f()
get2, post2 = f()

get1 and post1 will reference a different 'x' list than get2 and post2.

You could use exec to run the code objects. For example, if you had f defined as above, then

exec(f.func_code.co_consts[3])

would give

get

as output.

The inner function objects don't exist before the function f() is executed. If you want to get them you'll have to construct them yourself. That is definitely non-trivial because they might be closures that capture variables from the scope of the function and will anyway require poking around in objects that should probably be regarded as implementation details of the interpreter.

If you want to collect the functions with less repetition I recommend one of the following approaches:

a) Just put the functions in a class definition and return a reference to that class. A collection of related functions that are accessed by name smells awfully like a class.

b) Create a dict subclass that has a method for registering functions and use that as a decorator.

The code for this would look something like this:

class FunctionCollector(dict):
    def register(self, func):
        self[func.__name__] = func

def f():
    funcs = FunctionCollector()
    @funcs.register
    def get():
        return 'get'
    @funcs.register
    def put():
        return 'put'
    return funcs

c) Poke around in locals() and filter out the function with inspect.isfunction. (usually not a good idea)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top