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检查字符串是否是正确ISBN的方法
Jul 11 Python
Python通过RabbitMQ服务器实现交换机功能的实例教程
Jun 29 Python
对Python中plt的画图函数详解
Nov 07 Python
对python周期性定时器的示例详解
Feb 19 Python
Python3实现的判断回文链表算法示例
Mar 08 Python
python中yield的用法详解——最简单,最清晰的解释
Apr 04 Python
Python生成一个迭代器的实操方法
Jun 18 Python
使用python+whoosh实现全文检索
Dec 09 Python
tensorflow 实现数据类型转换
Feb 17 Python
Python容器类型公共方法总结
Aug 19 Python
python爬虫beautifulsoup解析html方法
Dec 07 Python
python 如何做一个识别率百分百的OCR
May 29 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
帅气的琦玉老师
2020/03/02 日漫
phpexcel导入excel数据使用方法实例
2013/12/24 PHP
php中mysql连接方式PDO使用详解
2015/02/25 PHP
10款实用的PHP开源工具
2015/10/23 PHP
PHP7匿名类用法分析
2016/09/26 PHP
Android AsyncTack 异步任务实例详解
2016/11/02 PHP
CI框架表单验证实例详解
2016/11/21 PHP
PHP文件系统管理(实例讲解)
2017/09/19 PHP
silverlight线程与基于事件驱动javascript引擎(实现轨迹回放功能)
2011/08/09 Javascript
JAVASCRIPT函数作用域和提前声明 分享
2013/08/22 Javascript
JS从数组中随机取出几个数组元素的方法
2016/08/02 Javascript
使用JavaScript判断手机浏览器是横屏还是竖屏问题
2016/08/02 Javascript
js实现的光标位置工具函数示例
2016/10/03 Javascript
Bootstrap的modal拖动效果
2016/12/25 Javascript
jQuery弹出窗口简单实现代码
2017/03/09 Javascript
在vue中获取dom元素内容的方法
2017/07/10 Javascript
页面缩放兼容性处理方法(zoom,Firefox火狐浏览器)
2017/08/29 Javascript
JS动画定时器知识总结
2018/03/23 Javascript
微信小程序之几种常见的弹框提示信息实现详解
2019/07/11 Javascript
OpenLayers加载缩放控件使用方法详解
2020/09/25 Javascript
[05:23]DOTA2-DPC中国联赛2月1日Recap集锦
2021/03/11 DOTA
python网络编程学习笔记(九):数据库客户端 DB-API
2014/06/09 Python
python统计文本文件内单词数量的方法
2015/05/30 Python
Python中关于Sequence切片的下标问题详解
2017/06/15 Python
python爬虫之自制英汉字典
2019/06/24 Python
Python绘制频率分布直方图的示例
2019/07/08 Python
Pandas分组与排序的实现
2019/07/23 Python
django 多对多表的创建和插入代码实现
2019/09/09 Python
印度尼西亚在线时尚购物网站:ZALORA印尼
2016/08/02 全球购物
蔻驰西班牙官网:COACH西班牙
2019/01/16 全球购物
捷克玩具商店:Bambule
2019/02/23 全球购物
环境工程与管理大学毕业生求职信
2013/10/02 职场文书
秋季婚礼证婚词
2014/01/11 职场文书
初一地理教学反思
2014/01/16 职场文书
2014年检验员工作总结
2014/11/19 职场文书
导游词之江南周庄
2019/12/06 职场文书