24

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

Does not matter who is calling the function , i want the the function name in which i declare this line

import inspect

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

def foo():
    print(whoami())

currently it prints foo , i want to print whoami

JamesThomasMoon
  • 4,639
  • 6
  • 33
  • 42
John Kaff
  • 1,679
  • 4
  • 14
  • 28
  • 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. –  Oct 16 '15 at 04: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. – starrify Oct 16 '15 at 04:06
  • 2
    inspect.stack()[0][3] ? – lsbbo Oct 16 '15 at 04:08
  • 1
    You probably meant to do: `print(whoami())` . Further, @hero is correct, you should access `inspect.stack()[0][3]` to get the name – Nir Alfasi Oct 16 '15 at 04:08

6 Answers6

42

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
26

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
  • 2
    @JohnKaff: I think you've got a case of the X/Y problem here, and should probably ask a new question about how best to log invocations of functions (with arguments, class methods, etc) in python – Eric Oct 16 '15 at 15:42
  • It's better than anything else. – babygame0ver Oct 27 '19 at 12:52
18

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")
Giovanni Cappellotto
  • 4,137
  • 1
  • 29
  • 31
Eric
  • 91,378
  • 50
  • 226
  • 356
  • Thanks Eric , i will try that. Is there any way to apply that decorator to all function of class – John Kaff Oct 16 '15 at 04:56
  • @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. – Eric Oct 16 '15 at 15:36
5

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'
JamesThomasMoon
  • 4,639
  • 6
  • 33
  • 42
3

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

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

Filip Happy
  • 457
  • 4
  • 15
0

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

ideasman42
  • 35,906
  • 32
  • 172
  • 287