45

I feel like I should know this, but I haven't been able to figure it out...

I want to get the name of a method--which happens to be an integration test--from inside it so it can print out some diagnostic text. I can, of course, just hard-code the method's name in the string, but I'd like to make the test a little more DRY if possible.

2
  • possible duplicate of How to get the function name as string in Python? Commented Dec 28, 2012 at 18:56
  • 1
    @DarenW It's not. Requesting the name of a function from a variable containing a function object and requesting the name of a function from within are two very different questions. Commented Feb 12, 2016 at 15:27

6 Answers 6

57

This seems to be the simplest way using module inspect:

import inspect
def somefunc(a,b,c):
    print "My name is: %s" % inspect.stack()[0][3]

You could generalise this with:

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

def somefunc(a,b,c):
    print "My name is: %s" % funcname()

Credit to Stefaan Lippens which was found via google.

Sign up to request clarification or add additional context in comments.

Comments

24

The answers involving introspection via inspect and the like are reasonable. But there may be another option, depending on your situation:

If your integration test is written with the unittest module, then you could use self.id() within your TestCase.

1 Comment

I just discovered that self.id() works in the unittest setUp() method (it returns the name of the test, not "setUp" itself), unlike the other solutions. Therefore, I'm changing this to the accepted answer for this particular question.
15

This decorator makes the name of the method available inside the function by passing it as a keyword argument.

from functools import wraps
def pass_func_name(func):
    "Name of decorated function will be passed as keyword arg _func_name"
    @wraps(func)
    def _pass_name(*args, **kwds):
        kwds['_func_name'] = func.func_name
        return func(*args, **kwds)
    return _pass_name

You would use it this way:

@pass_func_name
def sum(a, b, _func_name):
    print "running function %s" % _func_name
    return a + b

print sum(2, 4)

But maybe you'd want to write what you want directly inside the decorator itself. Then the code is an example of a way to get the function name in a decorator. If you give more details about what you want to do in the function, that requires the name, maybe I can suggest something else.

2 Comments

+1 on using a decorator over relying on implementation details
@MatthewTrevor To be honest I see a decorater relying on implementation details. According to stackoverflow.com/questions/251464/… it should be better to use .__name__ over .func_name. I agree with the basic idea, though.
10
# file "foo.py" 
import sys
import os

def LINE( back = 0 ):
    return sys._getframe( back + 1 ).f_lineno
def FILE( back = 0 ):
    return sys._getframe( back + 1 ).f_code.co_filename
def FUNC( back = 0):
    return sys._getframe( back + 1 ).f_code.co_name
def WHERE( back = 0 ):
    frame = sys._getframe( back + 1 )
    return "%s/%s %s()" % ( os.path.basename( frame.f_code.co_filename ),     
                            frame.f_lineno, frame.f_code.co_name )

def testit():
   print "Here in %s, file %s, line %s" % ( FUNC(), FILE(), LINE() )
   print "WHERE says '%s'" % WHERE()

testit()

Output:

$ python foo.py
Here in testit, file foo.py, line 17
WHERE says 'foo.py/18 testit()'

Use "back = 1" to find info regarding two levels back down the stack, etc.

Comments

2

I think the traceback module might have what you're looking for. In particular, the extract_stack function looks like it will do the job.

Comments

1

To elaborate on @mhawke's answer:

Rather than

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

You can use

def funcname():
    frame = inspect.currentframe().f_back
    return inspect.getframeinfo(frame).function

Which, on my machine, is about 5x faster than the original version according to timeit.

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.