Python中使用logging模块代替print(logging简明指南)


Posted in Python onJuly 09, 2014

替换print?print怎么了?

print 可能是所有学习Python语言的人第一个接触的东西。它最主要的功能就是往控制台 打印一段信息,像这样:

print 'Hello, logging!'

print也是绝大多数人用来调试自己的程序用的最多的东西,就像写js使用 console.log 一样那么自然。很多刚刚开始学习Python的新手甚至有一定经验的老手,都在使用print 来调试他们的代码。

比如这是一个我写的输出 斐波那契数列 的小程序,让我们来看看它的代码:

# -*- coding: utf-8 -*-

"""

A simple fibonacci program

"""

import argparse
parser = argparse.ArgumentParser(description='I print fibonacci sequence')

parser.add_argument('-s', '--start', type=int, dest='start',

                    help='Start of the sequence', required=True)

parser.add_argument('-e', '--end', type=int, dest='end',

                    help='End of the sequence', required=True)
def infinite_fib():

    a, b = 0, 1

    yield a

    yield b

    while True:

        #print 'Before caculation: a, b = %s, %s' % (a, b)

        a, b = b, a + b

        #print 'After caculation: a, b = %s, %s' % (a, b)

        yield b


def fib(start, end):

    for cur in infinite_fib():

        #print 'cur: %s, start: %s, end: %s' % (cur, start, end)

        if cur > end:

            return

        if cur >= start:

            #print 'Returning result %s' % cur

            yield cur
def main():

    args = parser.parse_args()

    for n in fib(args.start, args.end):

        print n,
if __name__ == '__main__':

    main()

让我们来看看它工作的怎么样:

$ python fib.py  -s 1 -e 100

1 1 2 3 5 8 13 21 34 55 89

$ python fib.py  -s 100 -e 1000

144 233 377 610 987

没有任何问题,程序正确的完成了它的功能。但等等, 程序里面的那一堆被注释掉的print语句是怎么回事?

原来,这是我编写这个小程序的过程中,用来 调试(DEBUG) 的输出信息,在我完成了这 个程序以后,我自然就把这些print给注释掉了。让我们来看看如果把这个print语句打开后结果会怎么样?

$ python fib.py  -s 1 -e 100

cur: 0, start: 1, end: 100

cur: 1, start: 1, end: 100

Returning result 1

1 Before caculation: a, b = 0, 1

After caculation: a, b = 1, 1

cur: 1, start: 1, end: 100

... ...

... ...

(不计其数的输出信息)

如你所见,所有的计算过程都被打印出来了。

写的时候加上print,提交代码的时候还得记得把print语句删掉/注释掉,为什么我们要忍受这样的麻烦事呢? 让我们来介绍我们的主角 logging ,它几乎就是为这种使用情景而生的。

更好的做法,使用logging模块

logging模块是Python内置的日志模块,使用它可以非常轻松的处理和管理日志输出。 logging模块最简单的用法,是直接使用basicConfig方法来对logging进行配置:

import logging
# 设置默认的level为DEBUG

# 设置log的格式

logging.basicConfig(

    level=logging.DEBUG,

    format="[%(asctime)s] %(name)s:%(levelname)s: %(message)s"

)
# 记录log

logging.debug(...)

logging.info(...)

logging.warn(...)

logging.error(...)

logging.critical(...)

这样配置完logging以后,然后使用``logging.debug``来替换所有的print语句就可以了。 我们会看到这样的输出:

[2014-03-18 15:17:45,216] root:cur: 0, start: 1, end: 100

[2014-03-18 15:17:45,216] root:DEBUG: cur: 1, start: 1, end: 100

[2014-03-18 15:17:45,216] root:DEBUG: Returning result 1

[2014-03-18 15:17:45,216] root:DEBUG: Before caculation: a, b = 0, 1

... ...

使用真正的logger

上面说的basicConfig方法可以满足你在绝大多数场景下的使用需求,但是basicConfig有一个 很大的缺点。

调用basicConfig其实是给root logger添加了一个handler,这样当你的程序和别的使用了 logging的第三方模块一起工作时,会影响第三方模块的logger行为。这是由logger的继承特性决定的。

所以我们需要使用真正的logger:

import logging
# 使用一个名字为fib的logger

logger = logging.getLogger('fib')
# 设置logger的level为DEBUG

logger.setLevel(logging.DEBUG)
# 创建一个输出日志到控制台的StreamHandler

hdr = logging.StreamHandler()

formatter = logging.Formatter('[%(asctime)s] %(name)s:%(levelname)s: %(message)s')

hdr.setFormatter(formatter)
# 给logger添加上handler

logger.addHandler(hdr)

这样再使用logger来进行日志输出就行了。不过这样的坏处就是代码量比basicConfig要大不少。 所以我建议如果是非常简单的小脚本的话,直接使用basicConfig就可以,如果是稍微大一些 项目,建议认真配置好logger。

动态控制脚本的所有输出

使用了logging模块以后,通过修改logger的log level,我们就可以方便的控制程序的输出了。 比如我们可以为我们的斐波那契数列添加一个 -v 参数,来控制打印所有的调试信息。

# 添加接收一个verbose参数

parser.add_argument('-v', '--verbose', action='store_true', dest='verbose',

                    help='Enable debug info')
# 判断verbose

if args.verbose:

    logger.setLevel(logging.DEBUG)

else:

    logger.setLevel(logging.ERROR)

这样,默认情况下,我们的小程序是不会打印调试信息的,只有当传入`-v/--verbose`的时候, 我们才会打印出额外的debug信息,就像这样:

$ python fib.py  -s 1 -e 100

1 1 2 3 5 8 13 21 34 55 89
$ python fib.py  -s 1 -e 100 -v

[2014-03-18 15:17:45,216] fib:DEBUG: cur: 0, start: 1, end: 100

[2014-03-18 15:17:45,216] fib:DEBUG: cur: 1, start: 1, end: 100

[2014-03-18 15:17:45,216] fib:DEBUG: Returning result 1

[2014-03-18 15:17:45,216] fib:DEBUG: Before caculation: a, b = 0, 1

... ...

如你所见,使用了logging以后,什么时候需要打印DEBUG信息,什么时候需要关闭, 一切变的无比简单。

所以,赶紧用logging替换掉你的脚本里的print吧!

延伸阅读

以上这些只是介绍了logging模块最简单的一些功能,作为print的替代品来使用,logging 模块还有很多非常强大好用的功能,比如从文件读取配置、各种各样的Handlers等等。 建议阅读一下logging的官方文档:

1.logging Logging facility for Python
2.Logging HOWTO

最后附上使用logging模块的斐波那契数列程序完整代码:

# -*- coding: utf-8 -*-

"""

A simple fibonacci program

"""

import argparse
parser = argparse.ArgumentParser(description='I print fibonacci sequence')

parser.add_argument('-s', '--start', type=int, dest='start',

                    help='Start of the sequence', required=True)

parser.add_argument('-e', '--end', type=int, dest='end',

                    help='End of the sequence', required=True)

parser.add_argument('-v', '--verbose', action='store_true', dest='verbose',

                    help='Enable debug info')
import logging
logger = logging.getLogger('fib')

logger.setLevel(logging.DEBUG)
hdr = logging.StreamHandler()

formatter = logging.Formatter('[%(asctime)s] %(name)s:%(levelname)s: %(message)s')

hdr.setFormatter(formatter)
logger.addHandler(hdr)


def infinite_fib():

    a, b = 0, 1

    yield a

    yield b

    while True:

        logger.debug('Before caculation: a, b = %s, %s' % (a, b))

        a, b = b, a + b

        logger.debug('After caculation: a, b = %s, %s' % (a, b))

        yield b


def fib(start, end):

    for cur in infinite_fib():

        logger.debug('cur: %s, start: %s, end: %s' % (cur, start, end))

        if cur > end:

            return

        if cur >= start:

            logger.debug('Returning result %s' % cur)

            yield cur
def main():

    args = parser.parse_args()

    if args.verbose:

        logger.setLevel(logging.DEBUG)

    else:

        logger.setLevel(logging.ERROR)
    for n in fib(args.start, args.end):

        print n,
if __name__ == '__main__':

    main()
Python 相关文章推荐
深度剖析使用python抓取网页正文的源码
Jun 11 Python
Python对两个有序列表进行合并和排序的例子
Jun 13 Python
python的描述符(descriptor)、装饰器(property)造成的一个无限递归问题分享
Jul 09 Python
Python内置的字符串处理函数详细整理(覆盖日常所用)
Aug 19 Python
使用python实现ANN
Dec 20 Python
python3+PyQt5实现自定义窗口部件Counters
Apr 20 Python
pandas重新生成索引的方法
Nov 06 Python
pandas条件组合筛选和按范围筛选的示例代码
Aug 26 Python
python使用协程实现并发操作的方法详解
Dec 27 Python
Python语言异常处理测试过程解析
Jan 08 Python
关于ResNeXt网络的pytorch实现
Jan 14 Python
Sentry错误日志监控使用方法解析
Nov 12 Python
Python中的魔法方法深入理解
Jul 09 #Python
gearman的安装启动及python API使用实例
Jul 08 #Python
python实现跨文件全局变量的方法
Jul 07 #Python
Python中的并发编程实例
Jul 07 #Python
Python编程语言的35个与众不同之处(语言特征和使用技巧)
Jul 07 #Python
python基于mysql实现的简单队列以及跨进程锁实例详解
Jul 07 #Python
python中使用urllib2获取http请求状态码的代码例子
Jul 07 #Python
You might like
杏林同学录(八)
2006/10/09 PHP
PHP中文分词 自动获取关键词介绍
2012/11/13 PHP
PHP入门教程之操作符与控制结构流程详解
2016/09/09 PHP
防止文件缓存的js代码
2013/01/10 Javascript
jquery实现metro效果示例代码
2013/09/06 Javascript
浏览器页面区域大小的js获取方法
2013/09/21 Javascript
javascript alert乱码的解决方法
2013/11/05 Javascript
javascript白色简洁计算器
2015/05/04 Javascript
js光标定位文本框回车表单提交问题的解决方法
2015/05/11 Javascript
jQuery基于json与cookie实现购物车的方法
2016/04/15 Javascript
解决jquery无法找到其他父级子集问题的方法
2016/05/10 Javascript
javascript特效实现——当前时间和倒计时效果的简单实例
2016/07/20 Javascript
浅谈JavaScript的闭包函数
2016/12/08 Javascript
浅谈vue路径优化之resolve
2017/10/13 Javascript
vue使用mint-ui实现下拉刷新和无限滚动的示例代码
2017/11/06 Javascript
详谈vue+webpack解决css引用图片打包后找不到资源文件的问题
2018/03/06 Javascript
vue.js获得当前元素的文字信息方法
2018/03/09 Javascript
Canvas实现微信红包照片效果
2018/08/21 Javascript
JS实现textarea通过换行或者回车把多行数字分割成数组并且去掉数组中空的值
2018/10/29 Javascript
es6数据变更同步到视图层的方法
2019/03/04 Javascript
nodejs微信开发之授权登录+获取用户信息
2019/03/17 NodeJs
Python编程中的for循环语句学习教程
2015/10/14 Python
Python字符串特性及常用字符串方法的简单笔记
2016/01/04 Python
Python数据结构之顺序表的实现代码示例
2017/11/15 Python
浅谈Python黑帽子取代netcat
2018/02/10 Python
Request的中断和ErrorHandler实例解析
2018/02/12 Python
Django框架 信号调度原理解析
2019/09/04 Python
HTML5+CSS3 实现灵动的动画 TAB 切换效果(DEMO)
2017/09/15 HTML / CSS
Alba Moda瑞士网上商店:独家意大利时尚女装销售
2016/11/28 全球购物
怀俄明州飞钓:Platte River Fly Shop
2017/12/28 全球购物
高中军训感言500字
2014/02/24 职场文书
任命书怎么写
2014/06/04 职场文书
杨善洲观后感
2015/06/04 职场文书
2016年学校党支部公开承诺书
2016/03/25 职场文书
《孙子兵法》:欲成大事者,需读懂这些致胜策略
2019/08/23 职场文书
毕业生自荐求职信书写的技巧
2019/08/26 职场文书