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

后端 未结 4 1439
耶瑟儿~
耶瑟儿~ 2020-12-11 06:54

Given the function

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

is there a way for

相关标签:
4条回答
  • 2020-12-11 06:54

    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)

    0 讨论(0)
  • 2020-12-11 07:10

    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.

    0 讨论(0)
  • 2020-12-11 07:13

    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.

    0 讨论(0)
  • 2020-12-11 07:17

    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.

    0 讨论(0)
提交回复
热议问题