Introspecting a given function's nested (local) functions in Python

杀马特。学长 韩版系。学妹 提交于 2019-11-27 07:07:22

问题


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.


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


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)



来源:https://stackoverflow.com/questions/1234672/introspecting-a-given-functions-nested-local-functions-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!