Finding the name of a function while defining it

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Dec 27 14:31:04 CET 2012


On Tue, 25 Dec 2012 18:00:38 -0800, Abhas Bhattacharya wrote:

> While I am defining a function, how can I access the name (separately as
> string as well as object) of the function without explicitly naming
> it(hard-coding the name)? For eg. I am writing like:
> def abc():
>     #how do i access the function abc here without hard-coding the name?

You can't easily get the function name from inside the function. But you 
*can* easily get the function name from outside the function, so the 
simple solution is to use a decorator to wrap the function with something 
that knows its name. For example:


import functools

def print_function_name(func):
    # Decorate func so that it prints a message when called.
    @functools.wraps(func)
    def inner(*args, **kwargs):
        print "Calling function %s" % func.__name__
        return func(*args, **kwargs)
    return inner


@print_function_name
def spam(n):
    return ' '.join(['spam']*n)

@print_function_name
def breakfast(n):
    return ' and '.join(['ham', 'eggs', spam(n)])


And then in use:

py> spam(3)
Calling function spam
'spam spam spam'
py> 
py> breakfast(5)
Calling function breakfast
Calling function spam
'ham and eggs and spam spam spam spam spam'


I recommend you use this solution if possible.

Unfortunately this doesn't help if you actually need the function name 
*inside* the function, for example:

def invert(n):
    if n != 0:
        return 1/n
    else:
        raise ZeroDivisionError(
            'divide by zero error in function %s' % ***MAGIC GOES HERE***)

(But note, why would I bother doing this? When the traceback prints, it 
already displays the function name. Why am I doing by hand what Python 
automatically does for me?)

If you really must do this, you can do it like this:


import traceback

def get_current_function_name():
    """If this looks like magic, that's because it is."""
    x = traceback.extract_stack(limit=2)
    return x[0][2]


def invert(n):
    if n != 0:
        return 1/n
    else:
        me = get_current_function_name()
        raise ZeroDivisionError('divide by zero error in func %s' % me)



-- 
Steven



More information about the Python-list mailing list