John Kaff
John Kaff

Reputation: 2075

Get current function name from inside that function using Python

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.

Upvotes: 40

Views: 50167

Answers (7)

Asclepius
Asclepius

Reputation: 63282

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>

Upvotes: 1

Filip Happy
Filip Happy

Reputation: 624

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

Upvotes: 7

JamesThomasMoon
JamesThomasMoon

Reputation: 7134

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'

Upvotes: 12

ideasman42
ideasman42

Reputation: 48038

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

Upvotes: 1

Eric
Eric

Reputation: 97571

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")

Upvotes: 19

user707650
user707650

Reputation:

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

Upvotes: 31

user707650
user707650

Reputation:

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

Upvotes: 57

Related Questions