1
votes

How can I determine whether a function was called using the function's name or by the name of an alias of that function?

I can inspect a function to get its name from within the body of a function by doing:

import inspect

def foo():
   print(inspect.stack()[0][3])

foo() # prints 'foo'

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

However, if I alias the function and try the same thing I get the original function name (not the alias)

bar = foo
bar() # prints 'foo'

I would like to be able to be able to do the following:

def foo():
    print(... some code goes here ...)

bar = foo

foo() # prints 'foo'
bar() # prints 'bar'
2
There's no guarantee the reference used to call your function was obtained from any name at all. It could have been l = [foo]; l[0]() or sorted(some_list, key=l[0]).user2357112 supports Monica
That's a good point, I guess in that case l[0]() should print l[0].bunji

2 Answers

1
votes

I have a (somewhat hacky) solution that relies on a regex to parse the function name out of a string. There might be a cleaner solution, but at least using inspect only this is the best I could find.

import inspect
import re


function_from_call = re.compile("\w+(?=\(\))")


def foo():
    _, call_frame, *_ = inspect.stack()
    _, _, _, _, call, *_ = call_frame
    print(re.search(function_from_call, str(call)).group())

bar = foo
bar()  # prints bar
foo()  # prints foo

Short explanation: First, I am grabbing the inspect frame of the call that resulted in a call to this function. Then, I am extracting the actual call string from this frame and I apply a regex to this call string that gives us the function name only.

Note: From an interpreter shell, inspect behaves differently and my code above produces an error because my regex cannot match an actual function name. An additional caveat is pointed out in a comment to this question by @user2357112: It is not obvious that a call is directly tied to a name, as in

l = [foo]; l[0]()

When run from a script, my solution will handle simple renaming cases properly (as the one given in this question) but I do not advocate using it since corner cases as the one above will result in confusing errors.

1
votes

Based on the limited knowledge I have of the scope of your problem, this works:

import inspect

def foo():
  print(inspect.stack()[1][4][0].strip())

foo()
bar = foo
bar()

Results:

foo()
bar()