user3412497
user3412497

Reputation: 93

How to get function object inside a function (Python)

I want to have something like

def x():
  print get_def_name()

but not necessarily know the name of x.

Ideally it would return 'x' where x would be the name of the function.

Upvotes: 2

Views: 12992

Answers (4)

TrueY
TrueY

Reputation: 7610

I found a similar solution as Vazirani's, but I did a step forward to get the function object based on the name. Here is my solution:

import inspect

def named_func():
    func_name = inspect.stack()[0].function
    func_obj = inspect.stack()[1].frame.f_locals[func_name]
    print(func_name, func_obj, func_obj.xxx)

named_func.xxx = 15
named_func()

Output is

named_func <function named_func at 0x7f3bc84622f0> 15

Unfortunately I cannot do this with lambda function. I keep trying.

Upvotes: 1

Tushar Vazirani
Tushar Vazirani

Reputation: 1088

You can do this by using Python's built-in inspect library.

You can read more of its documentation if you want to handle more complicated cases, but this snippet will work for you:

from inspect import getframeinfo, currentframe

def test_func_name():
    return getframeinfo(currentframe()).function

print(test_func_name())

Upvotes: 8

schesis
schesis

Reputation: 59118

Functions in Python are objects, and as it happens those objects do have an attribute containing the name they were defined with:

>>> def x():
...     pass
...
>>> print x.__name__
x

So, a naïve approach might be this:

>>> def x():
...     print x.__name__
... 
>>> x()
x

That seems to work. However, since you had to know the name of x inside the function in order to do that, you haven't really gained anything; you might have well just have done this:

def x():
    print "x"

In fact, though, it's worse than that, because the __name__ attribute only refers to the name the function was defined with. If it gets bound to another name, it won't behave as you expect:

>>> y = x
>>> y()
x

Even worse, if the original name is no longer around, it won't work at all:

>>> del x
>>> y()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in x
NameError: global name 'x' is not defined

This second problem is one you can actually get around, although it's not pretty. The trick is to write a decorator that can pass the function's name into it as an argument:

>>> from functools import wraps
>>> def introspective(func):
...     __name__ = func.__name__
...     @wraps(func)
...     def wrapper(*args, **kwargs):
...         return func(__name__=__name__, *args, **kwargs)
...     return wrapper
... 
>>> @introspective
... def x(__name__):
...     print __name__
... 
>>> x()
x
>>> y = x
>>> y()
x
>>> del x
>>> y()
x

... although as you can see, you're still only getting back the name the function was defined with, not the one it happens to be bound to right now.

In practice, the short (and correct) answer is "don't do that". It's a fundamental fact of Python that objects don't know what name (or names) they're bound to - if you think your function needs that information, you're doing something wrong.

Upvotes: 7

steveha
steveha

Reputation: 76695

This sounds like you want to declare an anonymous function and it would return a reference to the new function object.

In Python, you can get a trivial anonymous function object with lambda but for a complex function it must have a name. But any function object is in fact an object and you can pass references around to it, so the name doesn't matter.

# lambda
sqr = lambda n: n**2
assert sqr(2) == 4
assert sqr(3) == 9

# named function
def f(n):
    return n**2

sqr = f
assert sqr(2) == 4
assert sqr(3) == 9

Note that this function does have a name, f, but the name doesn't really matter here. We set the name sqr to the function object reference and use that name. We could put the function reference into a list or other data structure if we wanted to.

You could re-use the name of the function:

def f(n):
    return n**2
sqr = f

def f(n):
    return n**3
cube = f

So, while Python doesn't really support full anonymous functions, you can get the same effect. It's not really a problem that you have to give functions a name.

If you really don't want the function to have a name, you can unbind the name:

def f(n):
    return n**2

lst = [f]  # save function reference in a list
del(f)  # unbind the name

Now the only way to access this function is through the list; the name of the function is gone.

Upvotes: 0

Related Questions