Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Saturday, May 7, 2016

Python code to get current function into a variable?

Python code 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.

Answer by aaronasterling for Python code to get current function into a variable?


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.

Answer by jsbueno for Python code to get current function into a variable?


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.

Answer by bukzor for Python code to get current function into a variable?


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   Current function is   Current function is   

Answer by Triptych for Python code to get current function into a variable?


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.

Answer by kindall for Python code to get current function into a variable?


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 func_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, "func_code", None) is code:                  if getattr(func, "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.

Answer by kindall for Python code to get current function into a variable?


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()  

Answer by Florian for Python code to get current function into a variable?


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  

Answer by muodov for Python code to get current function into a variable?


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

Answer by someone for Python code to get current function into a variable?


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_var2 = f1(2)  f_var1(3)  f_var2(3)      def f3():      print(get_func())    f3()      def wrapper(func):      functools.wraps(func)      def wrapped(*args, **kwargs):          return func(*args, **kwargs)      return wrapped      @wrapper  def f4():      print(get_func())    f4()    f5 = lambda: get_func()    print(f5())  


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.