-
-
Save techtonik/2151727 to your computer and use it in GitHub Desktop.
# Public Domain, i.e. feel free to copy/paste | |
# Considered a hack in Python 2 | |
import inspect | |
def caller_name(skip=2): | |
"""Get a name of a caller in the format module.class.method | |
`skip` specifies how many levels of stack to skip while getting caller | |
name. skip=1 means "who calls me", skip=2 "who calls my caller" etc. | |
An empty string is returned if skipped levels exceed stack height | |
""" | |
stack = inspect.stack() | |
start = 0 + skip | |
if len(stack) < start + 1: | |
return '' | |
parentframe = stack[start][0] | |
name = [] | |
module = inspect.getmodule(parentframe) | |
# `modname` can be None when frame is executed directly in console | |
# TODO(techtonik): consider using __main__ | |
if module: | |
name.append(module.__name__) | |
# detect classname | |
if 'self' in parentframe.f_locals: | |
# I don't know any way to detect call from the object method | |
# XXX: there seems to be no way to detect static method call - it will | |
# be just a function call | |
name.append(parentframe.f_locals['self'].__class__.__name__) | |
codename = parentframe.f_code.co_name | |
if codename != '<module>': # top level usually | |
name.append( codename ) # function or a method | |
del parentframe | |
return ".".join(name) |
Thanks very much! This is a very useful function!
I have made one minor change to line 14. I noticed that when I was using this function to set the name of a logger at many points in my program, things seemed to start running pretty slowly. After profiling, it looks like this is due to line 14 (i.e., the call to inspect.stack
). Fortunately, a simplified function can be used instead, as shown below:
...
>>> import sys
>>> import inspect
>>>
>>> def stack_(frame):
... framelist = []
... while frame:
... framelist.append(frame)
... frame = frame.f_back
... return framelist
...
>>> %timeit stack_(sys._getframe(1))
100000 loops, best of 3: 3.09 µs per loop
>>> %timeit inspect.stack()
100 loops, best of 3: 8.36 ms per loop
While the simple stack_
function is not a drop-in replacement for inspect.stack
, it provides all the functionality required for caller_name
and is over 2000x faster.
Here is a modified version of the code, including an additional function _L
which can be used to return a logger named based on the current method/function context:
# Public Domain, i.e. feel free to copy/paste
# Considered a hack in Python 2
import inspect
import logging
import sys
def _L(skip=0):
'''Shorthand to get logger for current function frame.'''
return logging.getLogger(caller_name(skip + 1))
def caller_name(skip=2):
"""Get a name of a caller in the format module.class.method
`skip` specifies how many levels of stack to skip while getting caller
name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.
An empty string is returned if skipped levels exceed stack height
"""
def stack_(frame):
framelist = []
while frame:
framelist.append(frame)
frame = frame.f_back
return framelist
stack = stack_(sys._getframe(1))
start = 0 + skip
if len(stack) < start + 1:
return ''
parentframe = stack[start]
name = []
module = inspect.getmodule(parentframe)
# `modname` can be None when frame is executed directly in console
# TODO(techtonik): consider using __main__
if module:
name.append(module.__name__)
# detect classname
if 'self' in parentframe.f_locals:
# I don't know any way to detect call from the object method
# XXX: there seems to be no way to detect static method call - it will
# be just a function call
name.append(parentframe.f_locals['self'].__class__.__name__)
codename = parentframe.f_code.co_name
if codename != '<module>': # top level usually
name.append(codename) # function or a method
del parentframe
return ".".join(name)
thanks!!!
Think you,it's very useful~
I've never used Python before, is this too hard to use?
6 years later, but still want to say thanks!