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 Web框架Pylons中使用MongoDB的例子
Dec 03 Python
Python OS模块常用函数说明
May 23 Python
批处理与python代码混合编程的方法
May 19 Python
python+selenium实现163邮箱自动登陆的方法
Dec 31 Python
Python 在字符串中加入变量的实例讲解
May 02 Python
Php多进程实现代码
May 07 Python
深入浅析python 中的匿名函数
May 21 Python
20行python代码的入门级小游戏的详解
May 05 Python
python加载自定义词典实例
Dec 06 Python
在Pytorch中计算自己模型的FLOPs方式
Dec 30 Python
Ubuntu16.04安装python3.6.5步骤详解
Jan 10 Python
使用 Python 在京东上抢口罩的思路详解
Feb 27 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 字符串操作入门教程
2006/12/06 PHP
获取远程文件大小的php函数
2010/01/11 PHP
php 模拟 asp.net webFrom 按钮提交事件的思路及代码
2013/12/02 PHP
PHP CodeIgniter框架的工作原理研究
2015/03/30 PHP
浅析Laravel5中队列的配置及使用
2016/08/04 PHP
ThinkPHP实现简单登陆功能
2017/04/28 PHP
实例讲解PHP验证邮箱是否合格
2019/01/28 PHP
php多进程应用场景实例详解
2019/07/22 PHP
thinkphp框架类库扩展操作示例
2019/11/26 PHP
JS实现完全语义化的网页选项卡效果代码
2015/09/15 Javascript
如何利用JSHint减少JavaScript的错误
2016/08/23 Javascript
微信小程序 wxapp内容组件 icon详细介绍
2016/10/31 Javascript
Node.js五大应用性能技巧小结(必须收藏)
2017/08/09 Javascript
利用Javascript开发一个二维周视图日历
2017/12/14 Javascript
vue2.0实现的tab标签切换效果(内容可自定义)示例
2019/02/11 Javascript
微信小程序上传多图到服务器并获取返回的路径
2019/05/05 Javascript
javascript中call,apply,callee,caller用法实例分析
2019/07/24 Javascript
vue获取data数据改变前后的值方法
2019/11/07 Javascript
JavaScript实现公告栏上下滚动效果
2020/03/13 Javascript
[01:34]2014DOTA2展望TI 剑指西雅图VG战队专访
2014/06/30 DOTA
python实现中文输出的两种方法
2015/05/09 Python
关于不懂Chromedriver如何配置环境变量问题解决方法
2019/06/12 Python
对PyQt5基本窗口控件 QMainWindow的使用详解
2019/06/19 Python
PyTorch的深度学习入门之PyTorch安装和配置
2019/06/27 Python
python中时间、日期、时间戳的转换的实现方法
2019/07/06 Python
Win10系统下安装labelme及json文件批量转化方法
2019/07/30 Python
全面总结使用CSS实现水平垂直居中效果的方法
2016/03/10 HTML / CSS
美国最灵活的移动提供商:Tello
2017/07/18 全球购物
关于毕业的广播稿
2014/01/10 职场文书
资助贫困学生倡议书
2014/05/16 职场文书
5s标语大全
2014/06/23 职场文书
股东大会通知
2015/04/24 职场文书
初中重阳节活动总结
2015/05/05 职场文书
党员干部学法用法心得体会
2016/01/21 职场文书
竞选稿之小学班干部
2019/10/31 职场文书
go开发alertmanger实现钉钉报警
2021/07/16 Golang