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批量修改文件名的实现代码
Sep 01 Python
Python简单实现控制电脑的方法
Jan 22 Python
详解Django中间件执行顺序
Jul 16 Python
Sanic框架请求与响应实例分析
Jul 16 Python
python PrettyTable模块的安装与简单应用
Jan 11 Python
python+webdriver自动化环境搭建步骤详解
Jun 03 Python
python射线法判断一个点在图形区域内外
Jun 28 Python
python获取array中指定元素的示例
Nov 26 Python
Python实现把多维数组展开成DataFrame
Nov 30 Python
python 实现压缩和解压缩的示例
Sep 22 Python
关于多种方式完美解决Python pip命令下载第三方库的问题
Dec 21 Python
pygame面向对象的飞行小鸟实现(Flappy bird)
Apr 01 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
全国FM电台频率大全 - 22 重庆市
2020/03/11 无线电
php+oracle 分页类
2006/10/09 PHP
比较详细PHP生成静态页面教程
2012/01/10 PHP
php查询mssql出现乱码的解决方法
2014/12/29 PHP
php自动获取关键字的方法
2015/01/06 PHP
ThinkPHP3.2.3实现分页的方法详解
2016/06/03 PHP
php7安装yar扩展的方法详解
2017/08/03 PHP
PHP实现将多个文件压缩成zip格式并下载到本地的方法示例
2018/05/23 PHP
php命名空间设计思想、用法与缺点分析
2019/07/17 PHP
jquery tools之tabs 选项卡/页签
2009/07/25 Javascript
在jQuery1.5中使用deferred对象 着放大镜看Promise
2011/03/12 Javascript
jQuery动画效果animate和scrollTop结合使用实例
2014/04/02 Javascript
JavaScript给url网址进行encode编码的方法
2015/03/18 Javascript
举例讲解Node.js中的Writable对象
2015/07/29 Javascript
Bootstrap如何创建表单
2016/10/21 Javascript
Angularjs使用指令做表单校验的方法
2017/03/31 Javascript
vue-loader教程介绍
2017/06/14 Javascript
vue-cli之router基本使用方法详解
2017/10/17 Javascript
解决vue+webpack打包路径的问题
2018/03/06 Javascript
Vue 配合eiement动态路由,权限验证的方法
2018/09/26 Javascript
vue项目持久化存储数据的实现代码
2018/10/01 Javascript
Angular 多级路由实现登录页面跳转(小白教程)
2019/11/19 Javascript
Vue的Eslint配置文件eslintrc.js说明与规则介绍
2020/02/03 Javascript
无法使用pip命令安装python第三方库的原因及解决方法
2018/06/12 Python
python+opencv打开摄像头,保存视频、拍照功能的实现方法
2019/01/08 Python
python使用phoenixdb操作hbase的方法示例
2019/02/28 Python
西班牙香水和化妆品连锁店:Druni
2019/05/05 全球购物
be2台湾单身男女交友:全球网路婚姻介绍的领导品牌
2019/10/11 全球购物
女子职高个人自荐书
2014/02/01 职场文书
保护环境倡议书300字
2014/05/19 职场文书
竞聘自述材料
2014/08/25 职场文书
体育个人工作总结
2015/02/09 职场文书
英语投诉信范文
2015/07/03 职场文书
2015初中政教处工作总结
2015/07/21 职场文书
2015中学教学工作总结
2015/07/22 职场文书
mysql性能优化以及配置连接参数设置
2022/05/06 MySQL