How to Get Current Function into a Variable

How 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 __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.

Built-in variable to get current function

You can abstract that logic outside the function entirely by using a decorator (see this thorough answer if you're unfamiliar with decorators):

from functools import wraps

def autolist(func):
@wraps(func)
def wrapper(args):
if isinstance(args, list):
return [func(arg) for arg in args]
return func(args)
return wrapper

This decorator can be applied to any function requiring the pattern, which now only needs to implement the scalar case:

>>> @autolist
... def square(x):
... return x ** 2
...
>>> square(1)
1
>>> square([1, 2, 3])
[1, 4, 9]

If you're applying it to a method, as self implies, you'll also need to take that argument into account in the wrapper. For example, if the relevant argument is always the last one you could do:

def autolist(func):
@wraps(func)
def wrapper(*args):
*args, last_arg = args
if isinstance(last_arg, list):
return [func(*args, arg) for arg in last_arg]
return func(*args, last_arg)
return wrapper

This would work on methods, too:

>>> class Squarer:
... @autolist
... def square(self, x):
... return x ** 2
...
>>> Squarer().square(1)
1
>>> Squarer().square([1, 2, 3])
[1, 4, 9]

Determine function name from within that function (without using traceback)

Python doesn't have a feature to access the function or its name within the function itself. It has been proposed but rejected. If you don't want to play with the stack yourself, you should either use "bar" or bar.__name__ depending on context.

The given rejection notice is:

This PEP is rejected. It is not clear how it should be implemented or what the precise semantics should be in edge cases, and there aren't enough important use cases given. response has been lukewarm at best.

Is there a way to get the current function from within the current function?

Yes – arguments.callee is the current function.

NOTE: This is deprecated in ECMAScript 5, and may cause a performance hit for tail-call recursion and the like. However, it does work in most major browsers.

In your case, f1 will also work.

Calling variable defined inside one function from another function

One approach would be to make oneFunction return the word so that you can use oneFunction instead of word in anotherFunction :

def oneFunction(lists):
category = random.choice(list(lists.keys()))
return random.choice(lists[category])


def anotherFunction():
for letter in oneFunction(lists):
print("_", end=" ")

Another approach is making anotherFunction accept word as a parameter which you can pass from the result of calling oneFunction:

def anotherFunction(words):
for letter in words:
print("_", end=" ")
anotherFunction(oneFunction(lists))

And finally, you could define both of your functions in a class, and make word a member:

class Spam:
def oneFunction(self, lists):
category=random.choice(list(lists.keys()))
self.word=random.choice(lists[category])

def anotherFunction(self):
for letter in self.word:
print("_", end=" ")

Once you make a class, you have to instantiate an instance and access the member functions:

s = Spam()
s.oneFunction(lists)
s.anotherFunction()

get current function name inside that function using python

You probably want inspect.getframeinfo(frame).function:

import inspect

def whoami():
frame = inspect.currentframe()
return inspect.getframeinfo(frame).function

def foo():
print(whoami())

foo()

prints

whoami

Access a function variable outside the function without using global

You could do something along these lines (which worked in both Python v2.7.17 and v3.8.1 when I tested it/them):

def hi():
# other code...
hi.bye = 42 # Create function attribute.
sigh = 10

hi()
print(hi.bye) # -> 42

Functions are objects in Python and can have arbitrary attributes assigned to them.

If you're going to be doing this kind of thing often, you could implement something more generic by creating a function decorator that adds a this argument to each call to the decorated function.

This additional argument will give functions a way to reference themselves without needing to explicitly embed (hardcode) their name into the rest of the definition and is similar to the instance argument that class methods automatically receive as their first argument which is usually named self — I picked something different to avoid confusion, but like the self argument, it can be named whatever you wish.

Here's an example of that approach:

def add_this_arg(func):
def wrapped(*args, **kwargs):
return func(wrapped, *args, **kwargs)
return wrapped

@add_this_arg
def hi(this, that):
# other code...
this.bye = 2 * that # Create function attribute.
sigh = 10

hi(21)
print(hi.bye) # -> 42

Note

This doesn't work for class methods. Just use the instance argument, named self by convention, that's already passed to methods instead of the method's name. You can reference class-level attributes through type(self). See Function's attributes when in a class.

How to get a function name as a string?

my_function.__name__

Using __name__ is the preferred method as it applies uniformly. Unlike func_name, it works on built-in functions as well:

>>> import time
>>> time.time.func_name
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'builtin_function_or_method' object has no attribute 'func_name'
>>> time.time.__name__
'time'

Also the double underscores indicate to the reader this is a special attribute. As a bonus, classes and modules have a __name__ attribute too, so you only have remember one special name.



Related Topics



Leave a reply



Submit