熱線電話:13121318867

登錄
首頁精彩閱讀python中使用sys模板和logging模塊獲取行號和函數名的方法
python中使用sys模板和logging模塊獲取行號和函數名的方法
2018-05-17
收藏

python中使用sys模板和logging模塊獲取行號和函數名的方法

對于python,這幾天一直有兩個問題在困擾我:
1.python中沒辦法直接取得當前的行號和函數名。這是有人在論壇里提出的問題,底下一群人只是在猜測python為什么不像__file__一樣提供__line__和__func__,但是卻最終也沒有找到解決方案。
2.如果一個函數在不知道自己名字的情況下,怎么才能遞歸調用自己。這是我一個同事問我的,其實也是獲取函數名,但是當時也是回答不出來。

但是今晚!所有的問題都有了答案。
一切還要從我用python的logging模塊說起,logging中的format中是有如下選項的:

代碼如下:

%(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 (time.time()
                    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 record.getMessage(), computed just as
                    the record is emitted

也就是說,logging是能夠獲取到調用者的行號和函數名的,那會不會也可以獲取到自己的行號和函數名呢?
我們來看一下源碼,主要部分如下:

代碼如下:
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 = os.path.normcase(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 = self.findCaller()
        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 = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra)
    self.handle(record)

我簡單解釋一下,實際上是通過在currentframe函數中拋出一個異常,然后通過向上查找的方式,找到調用的信息。其中

代碼如下:
rv = (co.co_filename, f.f_lineno, co.co_name)

的三個值分別為文件名,行號,函數名。(可以去http://docs.python.org/library/sys.html來看一下代碼中幾個系統函數的說明)
OK,如果已經看懂了源碼,那獲取當前位置的行號和函數名相信也非常清楚了,代碼如下:

代碼如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
'''
#=============================================================================
#  FileName:        xf.py
#  Description:     獲取當前位置的行號和函數名
#  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()


輸入結果是:

代碼如下:
('callfunc', 24)

符合預期~~
哈哈,OK!現在應該不用再抱怨取不到行號和函數名了吧~

=============================================================================
后來發現,其實也可以有更簡單的方法,如下:

代碼如下:
import sys
def get_cur_info():
    print sys._getframe().f_code.co_name
    print sys._getframe().f_back.f_code.co_name
get_cur_info()

調用結果是:

代碼如下:
get_cur_info
<module>


數據分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數據分析師資訊
更多

OK
客服在線
立即咨詢
日韩人妻系列无码专区视频,先锋高清无码,无码免费视欧非,国精产品一区一区三区无码
客服在線
立即咨詢