How to get current function into a variable?
Asked Answered
P

10

37

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.

Panlogism answered 20/12, 2010 at 18:17 Comment(3)
I'll ask. Why do you want to do this?Lemieux
I'll suggest. Don't waste time trying to do this. Functions are already first-class objects.Lancelot
Functions being first-class objects is a reason why you should be able to get a reference to a function from itself, just as you should be able to get a reference to a class you're defining while you're defining it (a much more common request). Neither is supported by Python. This doesn't need to be runtime (eg. inspecting the stack); it can be performed at function binding time (when a function is created from its code object). I'm curious why he wants this too, though (the uses of the class case are much more obvious).Hypostyle
T
36

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 funcs:
                    return None
                funcs.append(func)
    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.

Towrey answered 22/12, 2010 at 4:9 Comment(12)
I haven't evaluated your answer for validity yet, but I'm upvoting for "give up the func".Panlogism
Ok, that's pretty cool. This is exactly what I was looking for.Panlogism
As a caveat, this is very CPython-specific.Towrey
here's a counter example. Like I said in my answer, there are a lot of corner cases.Equipoise
Ah, yeah, that's where functions share code objects... closures. Hm. For now, added a note that that's a corner case.Towrey
Code now detects this and returns None rather than the wrong function. I have another idea which I'll work on later.Towrey
Doesn't work for me in Py3. Used bukzor's answer successfully.Manwell
This strategy works in both CPython and PyPy, across Python 2.6, 2.7, and 3. The trick is changing the attribute names from func_code to __code__ and func_globals to __globals__. The real gotcha is that it's slow. About 25,000x slower than knowing the function reference. Fine for debugging uses, maybe not so much performance-needing code. The strategy of eval()ing a string function name found from the stack is much faster, albeit with its own tradeoffs (closures and such).Handmaiden
Unfortunately this strategy fails miserably with closures... just try f = lambda: lambda: None assert f().__code__ is f().__code__ assert f() is not f()Flasket
Hi @kindall. Do you have any idea how to solve this?Tymes
@Maggyero I don't think that's easily solvable using the gc approach. You'd have to inspect bound method objects, and there could be any number of those referring to the method of interest.Towrey
"give up the func" is a homophonic pun ("func" sounds like "funk"). When the "funk" is substituted, the phrase ceases to be a procedure reference and instead becomes a cultural reference to the hit song of the same name by Parliament Funkadelic. Puns are common in both the music of Parliament and in Python literature. Although a thematic break with the Pythonic tradition of Monty Python, which may tear the roof off the sucker, the homophonic substitution may remove faults, defects or shortcomings. You know, like arthritis, rheumatism or migraines. *puts on sunglasses*Headroom
E
16

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.

Equipoise answered 20/12, 2010 at 18:27 Comment(4)
The problem is that redefining the function is common practice in Python, with (but certainly not limited to) decorators. Whether that matters depends on what you're actually doing, of course, but if you really want the function currently executing, then that's not it.Hypostyle
@Glenn Maynard. Presumably the person that's writing the function that needs to be able to access itself would have control over the enclosing scope to make sure that either (a) such a redefinition did not occur, or (b) if it did occur, the original function was preserved under a different name that could then be used to access it. The bottom of the call stack is easy.Equipoise
Avoiding the need to do that is usually the reason for asking this question in the first place (that and recursive lambdas, I suppose).Hypostyle
LOL. This is kinda dumb and simple, but I haven't actually thought of it. This does what I need, thank you.Sepaloid
B
16

This is what you asked for, as close as I can come. Tested in python versions 2.4, 2.6, 3.0.

#!/usr/bin/python
def getfunc():
    from inspect import currentframe, getframeinfo
    caller = currentframe().f_back
    func_name = getframeinfo(caller)[2]
    caller = caller.f_back
    from pprint import pprint
    func = caller.f_locals.get(
            func_name, caller.f_globals.get(
                func_name
        )
    )

    return func

def main():
    def inner1():
        def inner2():
            print("Current function is %s" % getfunc())
        print("Current function is %s" % getfunc())
        inner2()
    print("Current function is %s" % getfunc())
    inner1()


#entry point: parse arguments and call main()
if __name__ == "__main__":
    main()

Output:

Current function is <function main at 0x2aec09fe2ed8>
Current function is <function inner1 at 0x2aec09fe2f50>
Current function is <function inner2 at 0x2aec0a0635f0>
Brennan answered 20/12, 2010 at 19:53 Comment(5)
This doesn't really offer any advantages over just using the name of that the function is defined with. You're getting the name of the code object which will not be the "name" of the function if any redefinition has occurred.Equipoise
@aaronasterling: That's true (read your other notes about closures/decorators). But he does get it without repeating himself. I agree in not using this beyond demoing some example code where it's nice to print function names...Manwell
@Equipoise Sorry if this question is too basic but I was learning from this example. What is the purpose feeding "caller.f_locals.get()" with "func_name" plus "func_name" as seen by globals, instead of just passing func_name alone? Also, what does get() does when you pass two arguments instead of one?Masson
@chrisfromlocalgroup: pydoc dict docs.python.org/3.5/library/stdtypes.html#dict.getBrennan
@Brennan It all makes sense now, thanks for your help.Masson
T
12

Here's another possibility: a decorator that implicitly passes a reference to the called function as the first argument (similar to self in bound instance methods). You have to decorate each function that you want to receive such a reference, but "explicit is better than implicit" as they say.

Of course, it has all the disadvantage of decorators: another function call slightly degrades performance, and the signature of the wrapped function is no longer visible.

import functools

def gottahavethatfunc(func):

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return func(func, *args, **kwargs)

    return wrapper

The test case illustrates that the decorated function still gets the reference to itself even if you change the name to which the function is bound. This is because you're only changing the binding of the wrapper function. It also illustrates its use with a lambda.

@gottahavethatfunc
def quux(me):
    return me

zoom = gottahavethatfunc(lambda me: me)

baz, quux = quux, None

print baz()
print zoom()

When using this decorator with an instance or class method, the method should accept the function reference as the first argument and the traditional self as the second.

class Demo(object):

    @gottahavethatfunc
    def method(me, self):
        return me

print Demo().method()

The decorator relies on a closure to hold the reference to the wrapped function in the wrapper. Creating the closure directly might actually be cleaner, and won't have the overhead of the extra function call:

def my_func():
    def my_func():
        return my_func
    return my_func
my_func = my_func()

Within the inner function, the name my_func always refers to that function; its value does not rely on a global name that may be changed. Then we just "lift" that function to the global namespace, replacing the reference to the outer function. Works in a class too:

class K(object):
    def my_method():
        def my_method(self):
             return my_method
        return my_method
    my_method = my_method()
Towrey answered 22/12, 2010 at 17:31 Comment(1)
A bit messy, but it shouldn't have any edge cases as far as I can tell.Nealneala
C
6

I just define in the beginning of each function a "keyword" which is just a reference to the actual name of the function. I just do this for any function, if it needs it or not:

def test():
    this=test
    if not hasattr(this,'cnt'):
        this.cnt=0
    else:
        this.cnt+=1
    print this.cnt
Cavalier answered 3/11, 2011 at 12:5 Comment(2)
whoops! I'm getting Undefined variable on your "this = test" line... and why wouldn't I?Fullblown
@mikerodent I suspect you copied and pasted this=test but your function is not named test. You have to put the name of the function in there at least once. That is what the OP was trying to avoid.Yoke
K
5

The call stack does not keep a reference to the function itself - although the running frame as a reference to the code object that is the code associated to a given function.

(Functions are objects with code, and some information about their environment, such as closures, name, globals dictionary, doc string, default parameters and so on).

Therefore if you are running a regular function, you are better of using its own name on the globals dictionary to call itself, as has been pointed out.

If you are running some dynamic, or lambda code, in which you can't use the function name, the only solution is to rebuild another function object which re-uses thre currently running code object and call that new function instead.

You will loose a couple of things, like default arguments, and it may be hard to get it working with closures (although it can be done).

I have written a blog post on doing exactly that - calling anonymous functions from within themselves - I hope the code in there can help you:

http://metapython.blogspot.com/2010/11/recursive-lambda-functions.html

On a side note: avoid the use o inspect.stack -- it is too slow, as it rebuilds a lot of information each time it is called. prefer to use inspect.currentframe to deal with code frames instead.

This may sounds complicated, but the code itself is very short - I am pasting it bellow. The post above contains more information on how this works.

from inspect import currentframe
from types import FunctionType

lambda_cache = {}

def myself (*args, **kw):
    caller_frame = currentframe(1)
    code = caller_frame.f_code
    if not code in lambda_cache:
        lambda_cache[code] = FunctionType(code, caller_frame.f_globals)
    return lambda_cache[code](*args, **kw)

if __name__ == "__main__":
    print "Factorial of 5", (lambda n: n * myself(n - 1) if n > 1 else 1)(5)

If you really need the original function itself, the "myself" function above could be made to search on some scopes (like the calling function global dictionary) for a function object which code object would match with the one retrieved from the frame, instead of creating a new function.

Kinsfolk answered 20/12, 2010 at 18:53 Comment(2)
@Glenn: I never said otherwise. :-)Kinsfolk
It had to be said. By the way, it'd be safer in edge cases to use a (code, globals) tuple as the lambda_cache key. One other thing you'll lose is function attributes.Hypostyle
A
4

sys._getframe(0).f_code returns exactly what you need: the codeobject being executed. Having a code object, you can retrieve a name with codeobject.co_name

Aerostatics answered 18/9, 2014 at 13:25 Comment(2)
Note from the reference: "This function should be used for internal and specialized purposes only" - because this is not guaranteed to work across different Python implementations.Madi
True, but this kind of metadata will always be implementation-specific by definition. This will work in CPythonAerostatics
L
1

OK after reading the question and comments again, I think this is a decent test case:

def foo(n):
  """ print numbers from 0 to n """
  if n: foo(n-1)
  print n

g = foo    # assign name 'g' to function object
foo = None # clobber name 'foo' which refers to function object
g(10)      # dies with TypeError because function object tries to call NoneType

I tried solving it by using a decorator to temporarily clobber the global namespace and reassigning the function object to the original name of the function:

def selfbind(f):
   """ Ensures that f's original function name is always defined as f when f is executed """
   oname = f.__name__
   def g(*args, **kwargs):

      # Clobber global namespace
      had_key = None
      if globals().has_key(oname):
         had_key = True
         key = globals()[oname]
      globals()[oname] = g

      # Run function in modified environment
      result = f(*args, **kwargs)

      # Restore global namespace
      if had_key: 
         globals()[oname] = key
      else:
         del globals()[oname]

      return result

   return g

@selfbind
def foo(n):
   if n: foo(n-1)
   print n

g = foo   # assign name 'g' to function object
foo = 2   # calling 'foo' now fails since foo is an int
g(10)     # print from 0..10, even though foo is now an int
print foo # prints 2 (the new value of Foo)

I'm sure I haven't thought through all the use cases. The biggest problem I see is the function object intentionally changing what its own name points to (an operation which would be overwritten by the decorator), but that should be ok as long as the recursive function doesn't redefine its own name in the middle of recursing.

Still not sure I'd ever need to do this, but thinking about was interesting.

Lemieux answered 20/12, 2010 at 22:38 Comment(2)
A few issues come to mind, but the most critical is threads; multiple threads can call the function in parallel, and return from it in a different order than they entered. Also, if the global scope redefines foo, it probably did so for a reason; if calling g makes a call to something in the global scope that uses foo (the integer), it'll break. I'm fairly certain that the only clean way to do this is with language support--a native call that returns the function object.Hypostyle
Note that if all you (or the OP) want to do is define a recursive function without worrying about it reference to itself being clobbered, you can just nest the recursive function inside another function.Hypostyle
K
1

Here a variation (Python 3.5.1) of the get_referrers() answer, which tries to distinguish between closures that are using the same code object:

import functools
import gc
import inspect

def get_func():
    frame = inspect.currentframe().f_back
    code = frame.f_code
    return [
        referer
        for referer in gc.get_referrers(code)
        if getattr(referer, "__code__", None) is code and
        set(inspect.getclosurevars(referer).nonlocals.items()) <=
        set(frame.f_locals.items())][0]

def f1(x):
    def f2(y):
        print(get_func())
        return x + y
    return f2

f_var1 = f1(1)
f_var1(3)
# <function f1.<locals>.f2 at 0x0000017235CB2C80>
# 4

f_var2 = f1(2)
f_var2(3)
# <function f1.<locals>.f2 at 0x0000017235CB2BF8>
# 5

def f3():
    print(get_func())    

f3()
# <function f3 at 0x0000017235CB2B70>

def wrapper(func):
    functools.wraps(func)
    def wrapped(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapped

@wrapper
def f4():
    print(get_func())    

f4()
# <function f4 at 0x0000017235CB2A60>

f5 = lambda: get_func()    

print(f5())
# <function <lambda> at 0x0000017235CB2950>
Kindness answered 8/5, 2016 at 1:41 Comment(0)
K
0

Correction of my previous answer, because the subdict check already works with "<=" called on dict_items and the additional set() calls result in problems, if there are dict-values which are dicts themself:

import gc
import inspect


def get_func():
    frame = inspect.currentframe().f_back
    code = frame.f_code
    return [
        referer
        for referer in gc.get_referrers(code)
        if getattr(referer, "__code__", None) is code and
        inspect.getclosurevars(referer).nonlocals.items() <=
        frame.f_locals.items()][0]
Kindness answered 8/5, 2016 at 11:37 Comment(1)
Why don't you just edit your previous answer instead of creating a new one?Retch

© 2022 - 2024 — McMap. All rights reserved.