5 Best Ways to Retrieve a Function Name in Python

๐Ÿ’ก Problem Formulation: In Python programming, there might be instances where we need to fetch a functionโ€™s name (e.g., for debugging or logging purposes). For example, given a function def my_function(): pass, we want to retrieve the string "my_function".

Method 1: Using the function.__name__ Attribute

This method utilizes the built-in attribute __name__ available on every function object in Python. It returns the name of the function as a string. This approach is straightforward, easy to use, and is the standard way to get a function’s name.

Here’s an example:

def greeter():
    print("Hello World!")

print(greeter.__name__)

Output: greeter

The attribute __name__ of the function greeter is accessed directly to print the name of the function. It’s a simple and direct means to get the function name.

Method 2: Using the inspect Module

The inspect module provides several useful functions to get information about live objects, such as modules, classes, methods, functions, tracebacks, frame objects, and code objects. To get the function name, you can use inspect.getframeinfo() or inspect.currentframe() combined with function.__code__.

Here’s an example:

import inspect

def greeter():
    print("Hello World!")

frame_info = inspect.getframeinfo(inspect.currentframe())
print(frame_info.function)

Output: <module>

This snippet retrieves the frame information for the current execution frame and gets the name of the function from it. However, this method has limited use when executed in the global module scope, as shown.

Method 3: Using the globals() Function

Python’s globals() function returns a dictionary representing the current global symbol table. This symbol table keeps track of all the global level variables including functions. You can iterate through this dictionary to match your function object and extract its name.

Here’s an example:

def greeter():
    print("Hi there!")

for func_name, func_obj in globals().items():
    if callable(func_obj) and func_obj == greeter:
        print(func_name)

Output: greeter

In this code, we search the global namespace for the function object that matches greeter and then print its name. This method is useful but may not be as straightforward or as performant as using __name__.

Method 4: Using a Function Wrapper

This method involves creating a wrapper function which takes a function as input and returns its __name__ attribute. This is a flexible solution that can be used as a utility function to retrieve names of functions passed to it.

Here’s an example:

def get_function_name(fun):
    return fun.__name__

def greeter():
    print("Hey there!")

print(get_function_name(greeter))

Output: greeter

Here, get_function_name() is a function that extracts the name of any function passed to it. While this adds an extra function call, it can be useful if additional processing is needed.

Bonus One-Liner Method 5: Using a Lambda Function

A lambda function can be used to create a one-liner that returns the function name. This can be handy for quick uses, especially in an interactive shell.

Here’s an example:

greeter = lambda: None
print((lambda f: f.__name__)(greeter))

Output: <lambda>

This one-liner uses a lambda function to retrieve the name of another lambda function. However, lambda functions do not have a meaningful name by default, resulting in the output ‘<lambda>’. This is useful for named functions.

Summary/Discussion

  • Method 1: __name__ Attribute. The simplest and most direct method. Cannot be used with unnamed functions like lambdas.
  • Method 2: inspect Module. Provides detailed introspection capabilities, but can be overkill for just getting a function name.
  • Method 3: globals() Function. Allows identification of a function name in the global scope. Less direct and potentially slower than method 1.
  • Method 4: Function Wrapper. Good for extensibility and additional handling, but slightly more verbose than method 1.
  • Method 5: Lambda Function. A concise one-liner, best used for quick tasks and named functionsโ€”not suitable for lambda functions themselves.