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
Anyone Know of a Good Python Based Web Crawler That I Could Use
Assigning String with Boolean Expression
Python Webdriver to Handle Pop Up Browser Windows Which Is Not an Alert
Embedding Ipython Qt Console in a Pyqt Application
When Should I Be Using Classes in Python
How to Use Valgrind with Python
How to Change the Host and Port That the Flask Command Uses
Importerror: No Module Named 'Bottle' - Pycharm
How to Load/Edit/Run/Save Text Files (.Py) into an Ipython Notebook Cell
Command Executed with Paramiko Does Not Produce Any Output
Python: My Function Returns "None" After It Does What I Want It To
How to Extract Info Within a #Shadow-Root (Open) Using Selenium Python
Expand the Line with Specified Width in Data Unit
Python: Tf-Idf-Cosine: to Find Document Similarity
How to Isolate Everything Inside of a Contour, Scale It, and Test the Similarity to an Image