40

I want to log all the names of functions where my code is going. It does not matter who is calling the function.

import inspect

def whoami():
    return inspect.stack()[1][3]

def foo():
    print(whoami())

Currently it prints foo. I want it to print whoami.

4
  • Do you want to call and execute the function, or just call the name? Because you're doing the latter now, without parentheses after whoami in the last line. Commented Oct 16, 2015 at 4:06
  • "currently it prints foo": your current sample code prints nothing, or at least it won't print foo. Please edit it and provide a valid example. Commented Oct 16, 2015 at 4:06
  • 2
    inspect.stack()[0][3] ? Commented Oct 16, 2015 at 4:08
  • 1
    You probably meant to do: print(whoami()) . Further, @hero is correct, you should access inspect.stack()[0][3] to get the name Commented Oct 16, 2015 at 4:08

7 Answers 7

57

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
Sign up to request clarification or add additional context in comments.

3 Comments

This worked for me: return inspect.getouterframes(inspect.currentframe())[1].function
Also using import inspect, while setting frame = inspect.currentframe() you can follow with either print(frame.f_code.co_name) or return frame.f_code.co_name which provides the current function's name.
@AndroidControl Indeed. One can also use currentframe().f_back.f_code.co_name as is noted in my answer to get the calling function's name.
33

Actually, Eric's answer points the way if this is about logging:

For my logging purpose i want to log all the names of functions where my code is going

You can adjust the formatter to log the function name:

import logging               

def whoami():
    logging.info("Now I'm there")

def foo():
    logging.info("I'm here")
    whoami()
    logging.info("I'm back here again")

logging.basicConfig(
    format="%(asctime)-15s [%(levelname)s] %(funcName)s: %(message)s",
    level=logging.INFO)
foo()

prints

2015-10-16 16:29:34,227 [INFO] foo: I'm here
2015-10-16 16:29:34,227 [INFO] whoami: Now I'm there
2015-10-16 16:29:34,227 [INFO] foo: I'm back here again

1 Comment

It's better than anything else.
20

For my logging purpose i want to log all the names of functions where my code is going

Have you considered decorators?

import functools
def logme(f):
    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        print(f.__name__)
        return f(*args, **kwargs)
    return wrapped


@logme
def myfunction():
    print("Doing some stuff")

2 Comments

Thanks Eric , i will try that. Is there any way to apply that decorator to all function of class
@JohnKaff: Yes, you can apply decorators to classes too. You'll want that decorator to iterate over all methods of the class object, and wrap them in this decorator.
12

Call sys._getframe() to get a frame class instance. The f_code.co_name member holds the function name.

sys._getframe(0).f_code.co_name

Add a simple helper function func_name() to wrap the call

import sys

def func_name(): 
    return sys._getframe(1).f_code.co_name

def func1():
    print(func_name())

func1()  # prints 'func1'

Comments

7

This simple reusable method returns a name of the caller/parent function:

import inspect

def current_method_name():
    # [0] is this method's frame, [1] is the parent's frame - which we want
    return inspect.stack()[1].function  

# Example:
def whoami():
    print(current_method_name())

whoami()

-> output is whoami

1 Comment

Although this works for getting the caller's name, note that inspect.stack is thought to be slow. An alternative is to use inspect.currentframe().f_back.f_code.co_name as in this answer
1

Adding an answer here as it can be useful to include the class name as well as the function.

This checks for self and cls convention, to include the class name.

def name_of_caller(frame=1):
    """
    Return "class.function_name" of the caller or just "function_name".
    """
    frame = sys._getframe(frame)
    fn_name = frame.f_code.co_name
    var_names = frame.f_code.co_varnames
    if var_names:
        if var_names[0] == "self":
            self_obj = frame.f_locals.get("self")
            if self_obj is not None:
                return type(self_obj).__name__ + "." + fn_name
        if var_names[0] == "cls":
            cls_obj = frame.f_locals.get("cls")
            if cls_obj is not None:
                return cls_obj.__name__ + "." + fn_name
    return fn_name

Comments

1

This is probably the fastest implementation. It avoids the use of additional inspect methods which can be slow or unnecessary.

Implementation:

from inspect import currentframe

def get_self_name() -> str:
    return currentframe().f_code.co_name

def get_caller_name() -> str:
    return currentframe().f_back.f_code.co_name

def get_parent_caller_name() -> str:
    return currentframe().f_back.f_back.f_code.co_name

Usage:

def actual_function_1():
    print('In actual_function_1:', get_self_name())

def actual_function_2():
    print('In actual_function_2:', get_caller_name())

def actual_function_3() -> None:
    print('In actual_function_3:', get_parent_caller_name())

actual_function_1()
actual_function_2()
actual_function_3()

Output:

In actual_function_1: get_self_name
In actual_function_2: actual_function_2
In actual_function_3: <module>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.