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封装对象实现时间效果
Apr 23 Python
Python中的测试模块unittest和doctest的使用教程
Apr 14 Python
python得到qq句柄,并显示在前台的方法
Oct 14 Python
浅谈python在提示符下使用open打开文件失败的原因及解决方法
Nov 30 Python
使用python将excel数据导入数据库过程详解
Aug 27 Python
Python numpy数组转置与轴变换
Nov 15 Python
django ORM之values和annotate使用详解
May 19 Python
利用python控制Autocad:pyautocad方式
Jun 01 Python
Python scrapy爬取小说代码案例详解
Jul 09 Python
python实现简单文件读写函数
Feb 25 Python
能让Python提速超40倍的神器Cython详解
Jun 24 Python
Python中的turtle画箭头,矩形,五角星
Mar 16 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禁用函数设置及查看方法详解
2016/07/25 PHP
thinkPHP中验证码的简单实现方法
2016/12/05 PHP
Yii全局函数用法示例
2017/01/22 PHP
php 可变函数使用小结
2018/06/12 PHP
php实现的rc4加密解密类定义与用法示例
2018/08/16 PHP
Yii 框架使用Forms操作详解
2020/05/18 PHP
Extjs4 GridPanel 的几种样式使用介绍
2013/04/18 Javascript
javascript将相对路径转绝对路径示例
2014/03/14 Javascript
Javascript学习笔记之函数篇(五) : 构造函数
2014/11/23 Javascript
JavaScript电子时钟倒计时
2016/01/09 Javascript
Javascript实现图片轮播效果(一)让图片跳动起来
2016/02/17 Javascript
HTML页面,测试JS对C函数的调用简单实例
2016/08/09 Javascript
AngularJS过滤器filter用法总结
2016/12/13 Javascript
node.js中debug模块的简单介绍与使用
2017/04/25 Javascript
vue.js移动端app实战1:初始配置详解
2017/07/24 Javascript
JavaScript实现焦点进入文本框内关闭输入法的核心代码
2017/09/20 Javascript
D3.js实现简洁实用的动态仪表盘的示例
2018/04/04 Javascript
jQuery实现监听下拉框选中内容发生改变操作示例
2018/07/13 jQuery
vue+element的表格实现批量删除功能示例代码
2018/08/17 Javascript
Vue中的循环及修改差值表达式的方法
2019/08/29 Javascript
js+css实现扇形导航效果
2020/08/18 Javascript
Python3 适合初学者学习的银行账户登录系统实例
2017/08/08 Python
Python深拷贝与浅拷贝用法实例分析
2019/05/05 Python
解决Django 在ForeignKey中出现 non-nullable field错误的问题
2019/08/06 Python
通过实例解析Python调用json模块
2019/12/11 Python
Python实现栈的方法详解【基于数组和单链表两种方法】
2020/02/22 Python
Python判断变量是否是None写法代码实例
2020/10/09 Python
Python爬取梨视频的示例
2021/01/29 Python
详解CSS3中常用的样式【基本文本和字体样式】
2020/10/20 HTML / CSS
老海军美国官网:Old Navy
2016/09/05 全球购物
世界上最好的精品店:Shoptiques
2018/02/05 全球购物
Viking Direct荷兰:购买办公用品
2019/06/20 全球购物
党建目标管理责任书
2014/07/25 职场文书
结婚通知短信大全
2015/04/17 职场文书
idea编译器vue缩进报错问题场景分析
2021/07/04 Vue.js
动画《新网球王子 U-17 WORLD CUP》希腊队PV公开
2022/04/02 日漫