python中使用sys模板和logging模块获取行号和函数名的方法


Posted in Python onApril 15, 2014

对于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>
Python 相关文章推荐
python实现的系统实用log类实例
Jun 30 Python
分析Python中设计模式之Decorator装饰器模式的要点
Mar 02 Python
Python处理中文标点符号大集合
May 14 Python
python3 线性回归验证方法
Jul 09 Python
Python Pandas对缺失值的处理方法
Sep 27 Python
Python使用指定字符长度切分数据示例
Dec 05 Python
python生成13位或16位时间戳以及反向解析时间戳的实例
Mar 03 Python
python如何进行矩阵运算
Jun 05 Python
5款实用的python 工具推荐
Oct 13 Python
Python爬虫Scrapy框架CrawlSpider原理及使用案例
Nov 20 Python
matlab xlabel位置的设置方式
May 21 Python
Python实现智慧校园自动评教全新版
Jun 18 Python
python 动态获取当前运行的类名和函数名的方法
Apr 15 #Python
python使用百度翻译进行中翻英示例
Apr 14 #Python
python使用xauth方式登录饭否网然后发消息
Apr 11 #Python
python判断、获取一张图片主色调的2个实例
Apr 10 #Python
Python使用新浪微博API发送微博的例子
Apr 10 #Python
一个检测OpenSSL心脏出血漏洞的Python脚本分享
Apr 10 #Python
Python删除指定目录下过期文件的2个脚本分享
Apr 10 #Python
You might like
php生成略缩图代码
2012/07/16 PHP
session 加入redis的实现代码
2016/07/15 PHP
Swoole扩展的6种模式深入详解
2021/03/04 PHP
图片自动缩小 点击放大
2008/07/07 Javascript
PPK 谈 JavaScript 的 this 关键字 [翻译]
2009/09/29 Javascript
为超链接加上disabled后的故事
2010/12/10 Javascript
JavaScript将相对地址转换为绝对地址示例代码
2013/07/19 Javascript
jquery 自定义容器下雨效果可将下雨图标改为其他
2014/04/23 Javascript
jquery实现页面百叶窗走马灯式翻滚显示效果的方法
2015/03/12 Javascript
JS提交form表单实例分析
2015/12/10 Javascript
js中class的点击事件没有效果的解决方法
2016/10/13 Javascript
JQuery学习总结【一】
2016/12/01 Javascript
canvas绘制的直线动画
2017/01/23 Javascript
js 数字、字符串、布尔值的转换方法(必看)
2017/04/07 Javascript
微信小程序媒体组件详解(视频,音乐,图片)
2017/09/19 Javascript
微信小程序使用image组件显示图片的方法【附源码下载】
2017/12/08 Javascript
node.js连接mysql与基本用法示例
2019/01/05 Javascript
js面向对象封装级联下拉菜单列表的实现步骤
2021/02/08 Javascript
[02:16]完美世界DOTA2联赛PWL S3 集锦第三期
2020/12/21 DOTA
python插入排序算法的实现代码
2013/11/21 Python
python字符串替换的2种方法
2014/11/30 Python
PyTorch CNN实战之MNIST手写数字识别示例
2018/05/29 Python
删除python pandas.DataFrame 的多重index实例
2018/06/08 Python
Django中的ajax请求
2018/10/19 Python
对Python中plt的画图函数详解
2018/11/07 Python
Gauss-Seidel迭代算法的Python实现详解
2019/06/29 Python
Python递归函数特点及原理解析
2020/03/04 Python
Python 如何对文件目录操作
2020/07/10 Python
PyCharm Ctrl+Shift+F 失灵的简单有效解决操作
2021/01/15 Python
详解Python+Selenium+ChromeDriver的配置和问题解决
2021/01/19 Python
如何写毕业求职自荐信
2013/11/06 职场文书
考核工作实施方案
2014/03/30 职场文书
党旗在我心中演讲稿
2014/09/15 职场文书
小学生毕业评语
2014/12/26 职场文书
Spring Security中用JWT退出登录时遇到的坑
2021/10/16 Java/Android
详解gantt甘特图可拖拽、编辑(vue、react都可用 highcharts)
2021/11/27 Vue.js