For python, there are two questions that have been bugging me for the past few days:.
There is no way to get the current line number and function name directly. This is an issue that was brought up in the forums, and a bunch of people just speculated why python doesn't provide __line__ and __func__ like __file__, but didn't end up finding a solution.
2. How can a function call itself recursively if it doesn't know its own name. This was asked by one of my coworkers, actually getting the function name as well, but at the time it was also unanswerable.
But tonight! All the questions were answered.
It all started with my use of python's logging module, where the format in logging has the following options.
%(name)s Name of the logger (logging channel)
%(levelno)s Numeric logging level for the message (DEBUG, INFO,
WARNING, ERROR, CRITICAL)
%(levelname)s Text logging level for the message ("DEBUG", "INFO",
"WARNING", "ERROR", "CRITICAL")
%(pathname)s Full pathname of the source file where the logging
call was issued (if available)
%(filename)s Filename portion of pathname
%(module)s Module (name portion of filename)
%(lineno)d Source line number where the logging call was issued
(if available)
%(funcName)s Function name
%(created)f Time when the LogRecord was created (()
return value)
%(asctime)s Textual time when the LogRecord was created
%(msecs)d Millisecond portion of the creation time
%(relativeCreated)d Time in milliseconds when the LogRecord was created,
relative to the time the logging module was loaded
(typically at application startup time)
%(thread)d Thread ID (if available)
%(threadName)s Thread name (if available)
%(process)d Process ID (if available)
%(message)s The result of (), computed just as
the record is emitted
That is, logging is able to get the caller's line number and function name, so will it also be able to get its own line number and function name?
Let's take a look at the source code, the main parts are as follows.
def currentframe():
"""Return the frame object for the caller's stack frame."""
try:
raise Exception
except:
return sys.exc_info()[2].tb_frame.f_back
def findCaller(self):
"""
Find the stack frame of the caller so that we can note the source
file name, line number and function name.
"""
f = currentframe()
#On some versions of IronPython, currentframe() returns None if
#IronPython isn't run with -X:Frames.
if f is not None:
f = f.f_back
rv = "(unknown file)", 0, "(unknown function)"
while hasattr(f, "f_code"):
co = f.f_code
filename = (co.co_filename)
if filename == _srcfile:
f = f.f_back
continue
rv = (co.co_filename, f.f_lineno, co.co_name)
break
return rv
def _log(self, level, msg, args, exc_info=None, extra=None):
"""
Low-level logging routine which creates a LogRecord and then calls
all the handlers of this logger to handle the record.
"""
if _srcfile:
#IronPython doesn't track Python frames, so findCaller throws an
#exception on some versions of IronPython. We trap it here so that
#IronPython can use logging.
try:
fn, lno, func = ()
except ValueError:
fn, lno, func = "(unknown file)", 0, "(unknown function)"
else:
fn, lno, func = "(unknown file)", 0, "(unknown function)"
if exc_info:
if not isinstance(exc_info, tuple):
exc_info = sys.exc_info()
record = (, level, fn, lno, msg, args, exc_info, func, extra)
(record)
I'll briefly explain that it's actually done by throwing an exception in the currentframe function and then finding the information about the call by looking up. where
rv = (co.co_filename, f.f_lineno, co.co_name)
The three values are file name, line number, and function name. (You can go to /library/ to see the description of several system functions in the code)
OK, if you have read the source code, then get the current position of the line number and function name I believe it is also very clear, the code is as follows.
#!/usr/bin/python
# -*- coding: utf-8 -*-
'''
#=============================================================================
# FileName:
# Description: Get the line number and function name of the current position.
# Version: 1.0
#=============================================================================
'''
import sys
def get_cur_info():
"""Return the frame object for the caller's stack frame."""
try:
raise Exception
except:
f = sys.exc_info()[2].tb_frame.f_back
return (f.f_code.co_name, f.f_lineno)
def callfunc():
print get_cur_info()
if __name__ == '__main__':
callfunc()
The input result is.
Meets expectations~
Now you don't have to complain that you can't get the line number and function name, right?
=============================================================================
It was later realized that there could actually be a simpler way to do this as well, as follows.
def get_cur_info():
print sys._getframe().f_code.co_name
print sys._getframe().f_back.f_code.co_name
get_cur_info()
The result of the call is.
<module>