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实现3行代码解简单的一元一次方程
Aug 18 Python
Python语言描述KNN算法与Kd树
Dec 13 Python
Python数据结构与算法之使用队列解决小猫钓鱼问题
Dec 14 Python
Python实现修改文件内容的方法分析
Mar 25 Python
Django处理文件上传File Uploads的实例
May 28 Python
kaggle+mnist实现手写字体识别
Jul 26 Python
基于python的ini配置文件操作工具类
Apr 24 Python
介绍一款python类型检查工具pyright(推荐)
Jul 03 Python
30秒学会30个超实用Python代码片段【收藏版】
Oct 15 Python
Python with标签使用方法解析
Jan 17 Python
Python3交互式shell ipython3安装及使用详解
Jul 11 Python
10张动图学会python循环与递归问题
Feb 06 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/04/06 PHP
CI框架中cookie的操作方法分析
2014/12/12 PHP
以文件形式缓存php变量的方法
2015/06/26 PHP
php构造函数与析构函数
2016/04/23 PHP
PHP将页面中点击数量高的链接进行高亮显示的方法
2016/05/30 PHP
使用JavaScript创建新样式表和新样式规则
2016/06/14 PHP
php操纵mysqli数据库的实现方法
2016/09/18 PHP
jquery URL参数判断,确定菜单样式
2010/05/31 Javascript
判断js对象是否拥有某一个属性的js代码
2013/08/16 Javascript
jquery checkbox实现单选小例
2013/11/27 Javascript
在AngularJS中使用jQuery的zTree插件的方法
2016/04/21 Javascript
jQuery简单实现MD5加密的方法
2017/03/03 Javascript
vue组件生命周期详解
2017/11/07 Javascript
微信小程序使用slider设置数据值及switch开关组件功能【附源码下载】
2017/12/09 Javascript
jQuery简单实现向列表动态添加新元素的方法示例
2017/12/25 jQuery
利用weixin-java-miniapp生成小程序码并直接返回图片文件流的方法
2019/03/29 Javascript
详解jQuery中的getAll()和cleanData()
2019/04/15 jQuery
axios封装,使用拦截器统一处理接口,超详细的教程(推荐)
2019/05/02 Javascript
浅谈v-for 和 v-if 并用时筛选条件方法
2019/11/07 Javascript
[54:10]Spirit vs NB Supermajor小组赛 A组败者组决赛 BO3 第一场 6.2
2018/06/03 DOTA
[01:17:55]VGJ.T vs Mineski 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/20 DOTA
Python中的map()函数和reduce()函数的用法
2015/04/27 Python
学习python分支结构
2019/05/17 Python
keras自定义回调函数查看训练的loss和accuracy方式
2020/05/23 Python
Django contrib auth authenticate函数源码解析
2020/11/12 Python
Tea Collection官网:一家位于旧金山的童装公司
2020/08/07 全球购物
27个经典Linux面试题及答案,你知道几个?
2013/01/10 面试题
本科生求职简历的自我评价
2013/10/21 职场文书
建筑设计学生的自我评价
2014/01/16 职场文书
优秀志愿者事迹材料
2014/02/03 职场文书
个人借款担保书
2014/04/02 职场文书
2014五年级班主任工作总结
2014/12/05 职场文书
学校党支部公开承诺书
2015/04/30 职场文书
2015财务年终工作总结范文
2015/05/22 职场文书
Vue监视数据的原理详解
2022/02/24 Vue.js
Python内置包对JSON文件数据进行编码和解码
2022/04/12 Python