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 01 Python
Numpy array数据的增、删、改、查实例
Jun 04 Python
详解python中TCP协议中的粘包问题
Mar 22 Python
Python实现二叉树的最小深度的两种方法
Sep 30 Python
在Pytorch中计算自己模型的FLOPs方式
Dec 30 Python
Python字典生成式、集合生成式、生成器用法实例分析
Jan 07 Python
python去除删除数据中\u0000\u0001等unicode字符串的代码
Mar 06 Python
Windows 下python3.8环境安装教程图文详解
Mar 11 Python
深入了解Python enumerate和zip
Jul 16 Python
flask开启多线程的具体方法
Aug 02 Python
Python面向对象多态实现原理及代码实例
Sep 16 Python
Sublime Text3最新激活注册码分享适用2020最新版 亲测可用
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
php实现的替换敏感字符串类实例
2014/09/22 PHP
php提示Warning:mysql_fetch_array() expects的解决方法
2014/12/16 PHP
php计算title标题相似比的方法
2015/07/29 PHP
PHP的Laravel框架中使用消息队列queue及异步队列的方法
2016/03/21 PHP
php HTML无刷新提交表单
2016/04/05 PHP
laravel利用中间件防止未登录用户直接访问后台的方法
2019/09/30 PHP
JS 实现BASE64_ENCODE和BASE64_DECODE(实例代码)
2013/11/13 Javascript
js实现的简单图片浮动效果完整实例
2016/05/10 Javascript
原生js仿jquery animate动画效果
2016/07/13 Javascript
JavaScript和JQuery获取DIV值的方法示例
2017/03/07 Javascript
详解使用nvm管理多版本node的方法
2017/08/30 Javascript
通过vue写一个瀑布流插件代码实例
2019/09/07 Javascript
python使用PyGame绘制图像并保存为图片文件的方法
2015/04/24 Python
Python全局变量用法实例分析
2016/07/19 Python
numpy.transpose对三维数组的转置方法
2018/04/17 Python
Python之批量创建文件的实例讲解
2018/05/10 Python
python opencv对图像进行旋转且不裁剪图片的实现方法
2019/07/09 Python
Flask框架实现的前端RSA加密与后端Python解密功能详解
2019/08/13 Python
Django模板语言 Tags使用详解
2019/09/09 Python
详解python uiautomator2 watcher的使用方法
2019/09/09 Python
keras多显卡训练方式
2020/06/10 Python
python和php哪个容易学
2020/06/19 Python
PyQt5的相对布局管理的实现
2020/08/07 Python
基于Python的图像阈值化分割(迭代法)
2020/11/20 Python
HTML5 声明兼容IE的写法
2011/05/16 HTML / CSS
红色康乃馨酒店:Red Carnation Hotels
2017/06/22 全球购物
高级文秘工作总结的自我评价
2013/09/28 职场文书
巧克力蛋糕店创业计划书
2014/01/14 职场文书
麦当劳辞职信范文
2014/01/18 职场文书
文字自荐书范文
2014/02/10 职场文书
学校爱心捐款倡议书
2014/05/13 职场文书
岗位安全生产责任书
2014/07/28 职场文书
再婚婚前财产协议书范本
2014/10/19 职场文书
《詹天佑》教学反思
2016/02/20 职场文书
《卧薪尝胆》读后感3篇
2019/12/26 职场文书
Win11 Beta 22621.601 和 22622.601今日发布 KB5017384修复内容汇总
2022/09/23 数码科技