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中装饰器的一个妙用
Feb 08 Python
Python import自定义模块方法
Feb 12 Python
python遍历目录的方法小结
Apr 28 Python
python利用rsa库做公钥解密的方法教程
Dec 10 Python
python判断一个集合是否为另一个集合的子集方法
May 04 Python
Python运维开发之psutil库的使用详解
Oct 18 Python
解决python 无法加载downsample模型的问题
Oct 25 Python
Python字典生成式、集合生成式、生成器用法实例分析
Jan 07 Python
django 多数据库及分库实现方式
Apr 01 Python
Python实现电视里的5毛特效实例代码详解
May 15 Python
使用pandas库对csv文件进行筛选保存
May 25 Python
Python+OpenCV图像处理——图像二值化的实现
Oct 24 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 数组二分法查找函数代码
2010/02/16 PHP
PHP基础陷阱题(变量赋值)
2012/09/12 PHP
PHP实现通过Luhn算法校验信用卡卡号是否有效
2015/03/23 PHP
PHP+swoole实现简单多人在线聊天群发
2016/01/19 PHP
PHP ADODB实现事务处理功能示例
2018/05/25 PHP
PHP array_shift()用法实例分析
2019/01/07 PHP
Prototype使用指南之string.js
2007/01/10 Javascript
javascript之大字符串的连接的StringBuffer 类
2007/05/08 Javascript
javascript 硬盘序列号+其它硬件信息
2008/12/23 Javascript
ASP SQL防注入的方法
2008/12/25 Javascript
使用Java实现简单的server/client回显功能的方法介绍
2013/05/03 Javascript
js简单实现交换Li的值
2014/05/22 Javascript
Jquery使用css方法改变样式实例
2015/05/18 Javascript
JS验证 只能输入小数点,数字,负数的实现方法
2016/10/07 Javascript
Vue2.0 从零开始_环境搭建操作步骤
2017/06/14 Javascript
element ui 表格动态列显示空白bug 修复方法
2018/09/04 Javascript
vue-router 按需加载 component: () =&gt; import() 报错的解决
2020/09/22 Javascript
vue 数据遍历筛选 过滤 排序的应用操作
2020/11/17 Javascript
element-ui 弹窗组件封装的步骤
2021/01/22 Javascript
详解Python中列表和元祖的使用方法
2015/04/25 Python
Python数据分析之获取双色球历史信息的方法示例
2018/02/03 Python
sklearn-SVC实现与类参数详解
2019/12/10 Python
记一次Django响应超慢的解决过程
2020/09/17 Python
python 窃取摄像头照片的实现示例
2021/01/08 Python
世界领先的电子书网站:eBooks.com(在线购买小说、非小说和教科书)
2019/03/30 全球购物
JPA的优势都有哪些
2013/07/04 面试题
《珍珠泉》教学反思
2014/02/20 职场文书
降消项目实施方案
2014/03/30 职场文书
人资专员岗位职责
2014/04/04 职场文书
计算机专业求职信
2014/06/02 职场文书
2014院党委领导班子对照检查材料思想汇报
2014/09/24 职场文书
加强作风建设演讲稿
2014/10/24 职场文书
烟台的海导游词
2015/02/02 职场文书
nginx proxy_cache 缓存配置详解
2021/03/31 Servers
我的收音机情缘
2022/04/05 无线电
Spring Cloud OpenFeign模版化客户端
2022/06/25 Java/Android