Skip to content

Instantly share code, notes, and snippets.

@JettJones
Created September 21, 2017 18:34
Show Gist options
  • Save JettJones/c236494013f22723c1822126df944b12 to your computer and use it in GitHub Desktop.
Save JettJones/c236494013f22723c1822126df944b12 to your computer and use it in GitHub Desktop.
performance of various ways to get the callers name in python
import sys
import inspect
import time
import traceback
def deeper(func, depth):
if depth > 0:
return deeper(func, depth-1)
else:
return func()
def no_stack():
# do no inspection, measure the cost of deeper()
return "name"
def show_stack():
name = inspect.stack()[1][3]
return name
def show_trace():
frame = traceback.extract_stack()[-2]
name = getattr(frame, 'name', frame[2])
return name
def show_limit():
frame = traceback.extract_stack(limit=2)[-2]
name = getattr(frame, 'name', frame[2])
return name
def sys_traceback():
frame = sys._getframe().f_back
frame_info = traceback.extract_stack(f=frame, limit=1)[0]
name = getattr(frame_info, 'name', frame_info[2])
return name
def sys_inspect():
frame = sys._getframe().f_back
name = inspect.getframeinfo(frame)[2]
return name
def inspect_inspect():
frame = inspect.currentframe().f_back
name = inspect.getframeinfo(frame)[2]
return name
def measure_time(func, repeat=1000, stack=50):
total = 0
for _ in range(repeat):
start = time.time()
deeper(func, stack)
span = time.time() - start
total = total + span
print("{0:.2f} sec".format(total))
print('no measurement')
measure_time(no_stack)
measure_time(no_stack, stack=200)
print('inspect.stack (run 10% as many times, because slow)')
measure_time(show_stack, repeat=100)
measure_time(show_stack, repeat=100, stack=200)
print('traceback.extract_stack')
measure_time(show_trace)
measure_time(show_trace, stack=200)
print('traceback.extract_stack + limit')
measure_time(show_limit)
measure_time(show_limit, stack=200)
print('sys.getframe + traceback')
measure_time(sys_traceback)
measure_time(sys_traceback, stack=200)
print('sys.getframe + inspect')
measure_time(sys_inspect)
measure_time(sys_inspect, stack=200)
print('inspect.currentframe + inspect')
measure_time(inspect_inspect)
measure_time(inspect_inspect, stack=200)
# testing inspect performance suggestions from:
# - https://stackoverflow.com/questions/41481722/python-traceback-performance-problems
@pirate
Copy link

pirate commented Jul 5, 2019

I found that getting the name from frame = sys._getframe() + frame.co_code.co_name was
faster in python3.7 than any of the methods listed above. In my testing it was still the
fastest even when co_code contained a 2000+ line function.

...

def sys_co_code():
    frame = sys._getframe().f_back
    return frame.f_code.co_name

...
print('sys.getframe + co_code')
measure_time(sys_co_code)
measure_time(sys_co_code, stack=200)
...

Yielded:

no measurement
0.01 sec
0.04 sec
inspect.stack (run 10% as many times, because slow)
0.44 sec
1.58 sec
traceback.extract_stack
0.18 sec
0.61 sec
traceback.extract_stack + limit
0.02 sec
0.06 sec
sys.getframe + traceback
0.02 sec
0.05 sec
sys.getframe + co_code
0.01 sec
0.04 sec
sys.getframe + inspect
0.11 sec
0.13 sec
inspect.currentframe + inspect
0.10 sec
0.13 sec

And to get the full module path and name together:

import sys

def current_function_name(above=1):
    """returns the calling function's __module__.__name__"""
    # https://gist.github.com/JettJones/c236494013f22723c1822126df944b12#gistcomment-2962311

    frame = sys._getframe()
    for frame_idx in range(0, above):
        frame = frame.f_back

    caller_module = frame.f_globals["__name__"]
    caller_name = frame.co_code.co_name
    return f'{caller_module}.{caller_name}'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment