Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get current function into a variable?

How can I get a variable that contains the currently executing function in Python? I don't want the function's name. I know I can use inspect.stack to get the current function name. I want the actual callable object. Can this be done without using inspect.stack to retrieve the function's name and then evaling the name to get the callable object?

Edit: I have a reason to do this, but it's not even a remotely good one. I'm using plac to parse command-line arguments. You use it by doing plac.call(main), which generates an ArgumentParser object from the function signature of "main". Inside "main", if there is a problem with the arguments, I want to exit with an error message that includes the help text from the ArgumentParser object, which means that I need to directly access this object by calling plac.parser_from(main).print_help(). It would be nice to be able to say instead: plac.parser_from(get_current_function()).print_help(), so that I am not relying on the function being named "main". Right now, my implementation of "get_current_function" would be:

import inspect     def get_current_function():     return eval(inspect.stack()[1][3]) 

But this implementation relies on the function having a name, which I suppose is not too onerous. I'm never going to do plac.call(lambda ...).

In the long run, it might be more useful to ask the author of plac to implement a print_help method to print the help text of the function that was most-recently called using plac, or something similar.

like image 327
Ryan C. Thompson Avatar asked Dec 20 '10 18:12

Ryan C. Thompson


People also ask

Can you assign a function to a variable in JavaScript?

It is possible to use a function expression and assign it to a regular variable, e.g. const factorial = function(n) {...} . But the function declaration function factorial(n) is compact (no need for const and = ). An important property of the function declaration is its hoisting mechanism.

How do you use a variable from a function to another?

The variable can be assigned to the function object inside the function body. So the variable exists only after the function has been called. Once the function has been called, the variable will be associated with the function object. This variable can now be used anywhere inside or outside any function.

How do you name a string as a function?

Use the __name__ Property to Get the Function Name in Python To access the __name__ property, just put in the function name without the parentheses and use the property accessor . __name__ . It will then return the function name as a string.


2 Answers

The stack frame tells us what code object we're in. If we can find a function object that refers to that code object in its __code__ attribute, we have found the function.

Fortunately, we can ask the garbage collector which objects hold a reference to our code object, and sift through those, rather than having to traverse every active object in the Python world. There are typically only a handful of references to a code object.

Now, functions can share code objects, and do in the case where you return a function from a function, i.e. a closure. When there's more than one function using a given code object, we can't tell which function it is, so we return None.

import inspect, gc  def giveupthefunc():     frame = inspect.currentframe(1)     code  = frame.f_code     globs = frame.f_globals     functype = type(lambda: 0)     funcs = []     for func in gc.get_referrers(code):         if type(func) is functype:             if getattr(func, "__code__", None) is code:                 if getattr(func, "__globals__", None) is globs:                     funcs.append(func)                     if len(funcs) > 1:                         return None     return funcs[0] if funcs else None 

Some test cases:

def foo():     return giveupthefunc()  zed = lambda: giveupthefunc()  bar, foo = foo, None  print bar() print zed() 

I'm not sure about the performance characteristics of this, but i think it should be fine for your use case.

like image 123
kindall Avatar answered Sep 17 '22 19:09

kindall


I recently spent a lot of time trying to do something like this and ended up walking away from it. There's a lot of corner cases.

If you just want the lowest level of the call stack, you can just reference the name that is used in the def statement. This will be bound to the function that you want through lexical closure.

For example:

def recursive(*args, **kwargs):     me = recursive 

me will now refer to the function in question regardless of the scope that the function is called from so long as it is not redefined in the scope where the definition occurs. Is there some reason why this won't work?

To get a function that is executing higher up the call stack, I couldn't think of anything that can be reliably done.

like image 34
aaronasterling Avatar answered Sep 21 '22 19:09

aaronasterling