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 序列化 pickle/cPickle模块使用介绍
Nov 30 Python
Python格式化压缩后的JS文件的方法
Mar 05 Python
使用Pyinstaller的最新踩坑实战记录
Nov 08 Python
Python进阶之递归函数的用法及其示例
Jan 31 Python
Python实现判断一行代码是否为注释的方法
May 23 Python
pandas 将list切分后存入DataFrame中的实例
Jul 03 Python
Python单元测试unittest的具体使用示例
Dec 17 Python
python定时按日期备份MySQL数据并压缩
Apr 19 Python
Python 解决OPEN读文件报错 ,路径以及r的问题
Dec 19 Python
Selenium使用Chrome模拟手机浏览器方法解析
Apr 10 Python
keras的load_model实现加载含有参数的自定义模型
Jun 22 Python
Python selenium模块实现定位过程解析
Jul 09 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
综合图片计数器
2006/10/09 PHP
PHP 解决utf-8和gb2312编码转换问题
2010/03/18 PHP
浅析php中常量,变量的作用域和生存周期
2013/08/10 PHP
php判断类是否存在函数class_exists用法分析
2014/11/14 PHP
了解PHP的返回引用和局部静态变量
2015/06/04 PHP
PHP面向对象程序设计之对象生成方法详解
2016/12/02 PHP
javascript 设置文本框中焦点的位置
2009/11/20 Javascript
关于JavaScript定义类和对象的几种方式
2010/11/09 Javascript
读jQuery之十 事件模块概述
2011/06/27 Javascript
js判断设备是否为PC并调整图片大小
2014/02/12 Javascript
JavaScript中Number.MAX_VALUE属性的使用方法
2015/06/04 Javascript
详解JavaScript ES6中的Generator
2015/07/28 Javascript
使用Sticky组件实现带sticky效果的tab导航和滚动导航的方法
2016/03/22 Javascript
深入解析桶排序算法及Node.js上JavaScript的代码实现
2016/07/06 Javascript
js倒计时简单实现代码
2016/08/11 Javascript
响应式表格之固定表头的简单实现
2016/08/26 Javascript
JS中常用的正则表达式
2016/09/29 Javascript
详解Vue快速零配置的打包工具——parcel
2018/01/16 Javascript
Vue-Router模式和钩子的用法
2018/02/28 Javascript
vue服务端渲染缓存应用详解
2018/09/12 Javascript
JavaScript 点击触发复制功能实例详解
2018/11/02 Javascript
微信小程序图片自适应实现解析
2020/01/21 Javascript
[45:52]2018DOTA2亚洲邀请赛 4.1小组赛 A组加赛 LGD vs Liquid
2018/04/02 DOTA
Python之PyUnit单元测试实例
2014/10/11 Python
剖析Python的Twisted框架的核心特性
2016/05/25 Python
python matlibplot绘制3D图形
2018/07/02 Python
selenium+python实现自动登陆QQ邮箱并发送邮件功能
2019/12/13 Python
pycharm使用技巧之自动调整代码格式总结
2020/11/04 Python
CSS3中文字镂空、透明值、阴影效果设置示例小结
2016/03/07 HTML / CSS
美国在线轮胎零售商:SimpleTire
2019/04/08 全球购物
越南母婴用品购物网站:Kids Plaza
2020/04/09 全球购物
项目计划书范文
2014/01/09 职场文书
优秀团队获奖感言
2014/02/19 职场文书
《画杨桃》教学反思
2014/04/13 职场文书
mybatis中sql语句CDATA标签的用法说明
2021/06/30 Java/Android
如何使用SQL Server语句创建表
2022/04/12 SQL Server