Question

A small bit of code will explain why I'm asking and why this is not a duplicate. (I hope)

>>> def foo():
...    return 1
... 
>>> bar=foo
>>> bar.__name__
'foo'

How do I get 'bar'?

I've tried inspect and frames, but everything I've found so far fails this test.

Was it helpful?

Solution

bar is just a reference to an already created object(foo), doing bar=foo means you created another reference to the same object.

In [62]: def foo():pass

In [63]: bar=foo

In [64]: spam=bar     #another reference to foo function object

In [65]: spam.__name__,bar.__name__
Out[65]: ('foo', 'foo')

In [66]: spam is foo,bar is foo
Out[66]: (True, True)

In [67]: import sys

In [68]: sys.getrefcount(foo)  # no of variable pointing to that object

Out[68]: 4           #3+1, 1 added by default by getrefcount()

OTHER TIPS

After you assign bar = foo, you have two names that both refer to the exact same value. There's no way in Python to distinguish between them. Assignment in Python never copies data, it just makes a name refer to a value, and a function is a value like any other. There is only one function, and it has only one __name__.

If you know foo then you can check globals() to see if other functions are assigned to that function, note that this will pick up all other references:

>>> function_reference_names  = [k for k, v in globals().iteritems() if hasattr(globals()[k], "func_name") and globals()[k].func_name == bar.__name__ and k != bar.__name__]
>>> function_reference_names
['bar']

But as others have pointed out, if you want to do this, your probably asking the wrong question.

Well it's an interesting question, can a function know what name it's called by? As far as I know, this piece of information is not stored in the stack or anywhere else, so to fetch it, we'll have to go into higher dimensions, or go meta, to manipulate the info of the source itself.

The result may not be useful, but it's funny :)

Below is the clumsy code:

import inspect
import io
import re

def get_my_name(func_obj):
    caller_frame = inspect.currentframe().f_back.f_back
    caller_mod = inspect.getmodule(caller_frame)
    mod_src = inspect.getsource(caller_mod)
    call_lineno = caller_frame.f_lineno

    stream = io.StringIO(mod_src)
    for i in range(0, call_lineno):
        line = stream.readline()
    m = re.findall('[_a-zA-Z0-9]+(?=\()', line)
    m = [fname for fname in m if caller_frame.f_locals[fname] == func_obj]
    return m

def some_func(n):
    print(get_my_name(some_func))
    return n*n

def caller():
    f = some_func
    return f(2)

caller()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top