阅读 536

猪行天下之Python基础——10.1 Python常用模块(上)

内容简述:

  • 1、time和datetime模块
  • 2、logging模块

PS:如果你想搜索安装某个模块或者发布一个自己的模块可以到移步到:pypi.org/


1、time和datetime时间模块


① 基本操作

代码示例如下

import time, datetime

# 获取当前时间
moment = time.localtime()
print("年:%s" % moment[0])
print("月:%s" % moment[1])
print("日:%s" % moment[2])
print("时:%s" % moment[3])
print("分:%s" % moment[4])
print("秒:%s" % (moment[5] + 1))
print("周几:%s" % (moment[6] + 1))
print("一年第几天:%s" % moment[7])
print("是否为夏令时:%s" % moment[8], end="\n\n")

# 格式化时间(这里要注意strftime和strptime是不一样的!!!)
moment1 = time.strftime('%Y-%m-%d %H:%M:%S')
moment2 = time.strftime('%a %b %d %H:%M:%S %Y', time.localtime())
moment3 = time.mktime(time.strptime(moment2, '%a %b %d %H:%M:%S %Y'))
print(moment1)
print(moment2)
print(moment3, end="\n\n")

# 获得当前时间戳
print(time.time())  # 秒级
print(int(round(time.time() * 1000)), end="\n\n")  # 毫秒级

# 获得当前时间(时间数组,还需strftime格式化下)
print(datetime.datetime.now(), end="\n\n")

# 时间戳转换为时间
# 方法一:
moment4 = 1512184082
moment5 = time.localtime(moment4)  # 转换成时间数组
print(time.strftime('%Y-%m-%d %H:%M:%S', moment5), end="\n\n")  # 格式化

# 方法二:
moment6 = datetime.datetime.utcfromtimestamp(moment4)
print(moment6)
moment7 = moment6.strftime('%a %b %d %H:%M:%S %Y')
print(moment7, end="\n\n")

# 代码延迟执行
time.sleep(5)
复制代码

运行结果如下

年:2019
月:3
日:14
时:11
分:41
秒:57
周几:4
一年第几天:73
是否为夏令时:0

2019-03-14 11:41:56
Thu Mar 14 11:41:56 2019
1552534916.0

1552534916.3338902
1552534916334

2019-03-14 11:41:56.333890

2017-12-02 11:08:02

2017-12-02 03:08:02
Sat Dec 02 03:08:02 2017
复制代码

② struct_time,字符串,时间戳之间的转换关系


③ Python中的时间日期格式化符号

如下表所示,参考时间为(20190314 13:53:41)

符号 描述 示例
%y 两位数的年份表示(00-99) 19
%Y 四位数的年份表示(000-9999) 2019
%m 月份(01-12) 03
%d 月内中的一天(0-31) 14
%H 24小时制小时数(0-23) 13
%I 12小时制小时数(01-12) 01
%M 分钟数(00=59) 53
%S 秒(00-59) 41
%a 星期几的英文简写 Thu
%A 星期几的英文 Thursday
%b 月份的英文简写 Mar
%B 月份的英文 March
%x 日期 03/14/19
%X 时间 13:59:04
%c 日期和时间 Thu Mar 14 13:54:56 2019
%j 一年中第几天 073
%p 以AM和PM的方式显示上午还是下午 PM
%U 一年中的第几周,周天为一周的第一天 10
%W 一年中的第几周,周一为一周的第一天 10
%w 一周中的第几天,周天为0,周一为1 4
%z,%Z 当前时区的名称
%% %号自身 %

④ 一些实用的代码片段

下面提供一些很实用的代码片段,用到的时候复制粘贴即可:

import datetime
import time

now = datetime.datetime.now()


# 获得当前时间的前/后几天,几小时,几秒,毫秒
# 如果是想获得时间戳可以直接调用int(time.mktime(求出来的时间.timetuple()))
def fetch_before_time(time_type, value, strf="%Y-%m-%d %H:%M:%S"):
    if time_type == 'days':
        if value > 0:
            return (datetime.datetime.now() + datetime.timedelta(days=value)).strftime(strf)
        else:
            return (datetime.datetime.now() - datetime.timedelta(days=value)).strftime(strf)
    elif time_type == 'hours':
        if value > 0:
            return (datetime.datetime.now() + datetime.timedelta(hours=value)).strftime(strf)
        else:
            return (datetime.datetime.now() - datetime.timedelta(hours=value)).strftime(strf)
    elif time_type == 'seconds':
        if value > 0:
            return (datetime.datetime.now() + datetime.timedelta(seconds=value)).strftime(strf)
        else:
            return (datetime.datetime.now() - datetime.timedelta(seconds=value)).strftime(strf)
    elif time_type == 'microseconds':
        if value > 0:
            return (datetime.datetime.now() + datetime.timedelta(microseconds=value)).strftime(strf)
        else:
            return (datetime.datetime.now() - datetime.timedelta(microseconds=value)).strftime(strf)


# 获得第二天凌晨的时间戳
def fetch_morning_timestamp():
    return int(time.time()) + (144000 - (int(time.time())) % 86400)


# 构造一个由起始事件到结束时间间所有的日期列表
def init_date_list(begin_date, end_date):
    date_list = []
    begin_date = datetime.datetime.strptime(str(begin_date), "%Y%m%d")
    end_date = datetime.datetime.strptime(str(end_date), "%Y%m%d")
    while begin_date <= end_date:
        date_str = begin_date.strftime("%Y%m%d")
        date_list.append(date_str)
        begin_date += datetime.timedelta(days=1)
    return date_list


if __name__ == '__main__':
    print("当前时间:", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    print(fetch_before_time('days'3))
    print(fetch_before_time('hours', -3))
    print(fetch_before_time('seconds'3))
    print("第二天早上的时间戳:", fetch_morning_timestamp())
    print("从20190101到20190301的日期列表:%s" % init_date_list(2019010120190301))
复制代码

运行结果如下

当前时间: 2019-03-14 15:44:58
2019-03-17 15:44:58
2019-03-14 18:44:58
2019-03-14 15:45:01
第二天早上的时间戳: 1552665600
从20190101到20190301的日期列表:['20190101', '20190102',...过长省略... '20190226', '20190227', '20190228', '20190301']
复制代码

2、logging日志模块

大部分的程序都会有「记录运行日志的需求」,而日志信息一般有这样几类:正常的程序运行日志调试错误或警告信息的输出等。而日常开发中我们需要把日志持久化到本地,进行一些观察和统计,错误排查等,如果只用print函数输出的话,显然有点捉襟见寸。在Python内置了一个日志模块:logging,它提供了标准的日志接口,支持日志分级和存储


① 日志分级

在开始正式学习logging前,我们先了解下「日志分级」,即:什么时候用什么等级的日志。如下表所示:

级别 建议什么时候使用
DEBUG 详细的信息,常用于问题诊断
INFO 记录关键节点信息,用于确认程序是否按照预期运行
WARNING 程序还是正常运行,但某些不期望的事情发生时记录的信息(如磁盘可用空间较低)
ERROR 由于更严重的问题导致某些功能不能正常运行时记录的信息
CRITICAL 发生严重错误,导致程序不能继续运行时记录的信息

打印各种级别的代码示例如下:

import logging

if __name__ == '__main__':
    # 获得一个Logger
    logger = logging.getLogger("Test")

    # logging提供的简单的配置方法,自行配置的话需要手动添加handler
    logging.basicConfig()

    # 设置输出的log级别(大于或等于此级别的才会输出),默认级别Warning
    logger.setLevel(logging.INFO)
    logger.debug("=== Debug 级别的信息 ==="# 不会输出
    logger.info("=== Info 级别的信息 ===")
    logger.warning("=== Warning 级别的信息 ===")
    logger.error("=== Error 级别的信息 ===")
    logger.critical("=== Critical 级别的信息 ===")
复制代码

运行结果如下

INFO:Test:=== Info 级别的信息 ===
WARNING:Test:=== Warning 级别的信息 ===
ERROR:Test:=== Error 级别的信息 ===
CRITICAL:Test:=== Critical 级别的信息 ===
复制代码

② 将日志写入到文件

日志默认是输出到Console(屏幕)上,如果我们想把详细的日志输出到log文件里,则需要用到handler了,理论上可以把日志输出到各种流中stderr文件socket等都可以,在logging中已经将各种流handler封装好了,你也可以继承StreamHandler类自己做一些定制,简单的把日志写入到文件中的代码示例如下:

import logging

if __name__ == '__main__':
    logger = logging.getLogger("Test")
    logger.setLevel(logging.INFO)
    # 输出到控制台
    logger.addHandler(logging.StreamHandler())
    # 输出到文件
    logger.addHandler(logging.FileHandler('test.log', encoding='UTF-8'))
    logger.debug("=== Debug 级别的信息 ===")
    logger.info("=== Info 级别的信息 ===")
    logger.warning("=== Warning 级别的信息 ===")
    logger.error("=== Error 级别的信息 ===")
    logger.critical("=== Critical 级别的信息 ===")
复制代码

运行结果如下(同时在目录下生成了一个test.log的文件):

=== Info 级别的信息 ===
=== Warning 级别的信息 ===
=== Error 级别的信息 ===
=== Critical 级别的信息 ===
复制代码

嗯,你可能有这样的需求,Console打印Warning以上的日志,而log文件保存Debug级别以上的日志,那么可以修改下上面的代码,修改后的代码如下:

if __name__ == '__main__':
    logger = logging.getLogger("Test")
    logger.setLevel(logging.INFO)

    # 输出到控制台
    s_handler = logging.StreamHandler()
    s_handler.setLevel(logging.WARNING)
    logger.addHandler(s_handler)

    # 输出到文件
    f_handler = logging.FileHandler('test.log', encoding='UTF-8')
    f_handler.setLevel(logging.DEBUG)
    logger.addHandler(f_handler)
    logger.debug("=== Debug 级别的信息 ===")
    logger.info("=== Info 级别的信息 ===")
    logger.warning("=== Warning 级别的信息 ===")
    logger.error("=== Error 级别的信息 ===")
    logger.critical("=== Critical 级别的信息 ===")
复制代码

运行结果如下

# 控制台输出:
=== Warning 级别的信息 ===
=== Error 级别的信息 ===
=== Critical 级别的信息 ===

# test.log文件:
=== Info 级别的信息 ===
=== Warning 级别的信息 ===
=== Error 级别的信息 ===
=== Critical 级别的信息 ===
复制代码

③ 定制日志输出格式

纠结完输出到那里,接着就输出日志的格式了,日志一般都是比较规范的,比如日志打印的时间类型等,而不会像我们这样随意拼接一段字符串,对于日志格式的定制可以通过logging模块Formatter组件来定制。basicConfig()中的handler 自带一个formatter,通过logging.basicConfig(**kwargs)函数进行定制,该函数可接收的关键字参数如下表所示。

参数 描述
filename 指定日志输出目标文件的文件名,设置后信息就不会打印到控制台
filemode 指定日志文件的打开模式,默认为'a',设置了filename这个才会生效
format 指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序
datefmt 指定日期/时间格式,该选项要在format中包含时间字段%(asctime)s时才有效
level 指定日志器的日志级别
stream 指定日志输出目标stream,不能和filename同时使用否则会引起ValueError异常
style Python 3.2新增,默认'%'指定format格式字符串的风格,可取值为'%'、'{'和'$'

format格式字符串的字段列表如下表所示:

参数 描述
%(asctime)s 日志发生的时间--人类可读时间,如:2003-07-08 16:49:45,896
%(created)f 日志发生的时间--时间戳,就是当时调用time.time()函数返回的值
%(relativeCreated)d 日志发生的时间相对于logging模块加载时间的相对毫秒数
%(msecs)d 日志发生时间的毫秒部分
%(levelname)s 该日志记录的文字形式的日志级别('DEBUG', 'INFO', 'WARNING',
'ERROR', 'CRITICAL')
%(levelno)s 该日志记录的数字形式的日志级别(10, 20, 30, 40, 50)
%(name)s 所使用的日志器名称,默认是'root',因为默认使用的是 rootLogger
%(message)s 日志记录的文本内容,通过 msg % args计算得到的
%(pathname)s 调用日志记录函数的源码文件的全路径
%(filename)s pathname的文件名部分,包含文件后缀
%(module)s filename的名称部分,不包含后缀
%(lineno)d 调用日志记录函数的源代码所在的行号
%(funcName)s 调用日志记录函数的函数名
%(process)d 进程ID
%(processName)s 进程名称,Python 3.1新增
%(thread)d 线程ID
%(thread)s 线程名称

简单的使用代码示例如下

import logging

if __name__ == '__main__':
    logger = logging.getLogger("Test")
    logging.basicConfig(level=logging.INFO,
                        format="%(asctime)s %(process)d:%(processName)s- %(levelname)s === %(message)s",
                        datefmt="%Y-%m-%d %H:%M:%S %p")

    logger.debug("Debug 级别的信息")
    logger.info("Info 级别的信息")
    logger.warning("Warning 级别的信息")
    logger.error("Error 级别的信息")
    logger.critical("Critical 级别的信息")
复制代码

运行结果如下

2019-03-14 16:39:02 PM 8628:MainProcess- INFO === Info 级别的信息
2019-03-14 16:39:02 PM 8628:MainProcess- WARNING === Warning 级别的信息
2019-03-14 16:39:02 PM 8628:MainProcess- ERROR === Error 级别的信息
2019-03-14 16:39:02 PM 8628:MainProcess- CRITICAL === Critical 级别的信息
复制代码

另外要注意一点basicConfig没有设置编码的属性,如果想把日志写入到文件里,而日志里又有中文的话,只能通过一开始那种设置FileHandler对象的方式!除了通过basicConfig()设置日志格式,还可以自定义一个Formatter对象,然后调用setFormatter函数进行设置。使用代码示例如下:

import logging

if __name__ == '__main__':
    logger = logging.getLogger("Test")
    logger.setLevel(logging.INFO)
    # 自定义Formatter对象
    fmt = logging.Formatter("%(asctime)s %(process)d:%(processName)s- %(levelname)s === %(message)s",
                            datefmt="%Y-%m-%d %H:%M:%S %p")
    # 输出到控制台
    s_handler = logging.StreamHandler()
    s_handler.setLevel(logging.WARNING)
    s_handler.setFormatter(fmt)
    logger.addHandler(s_handler)
    # 输出到文件
    f_handler = logging.FileHandler('test.log', encoding='UTF-8')
    f_handler.setLevel(logging.DEBUG)
    f_handler.setFormatter(fmt)
    logger.addHandler(f_handler)
    logger.debug("Debug 级别的信息")
    logger.info("Info 级别的信息")
    logger.warning("Warning 级别的信息")
    logger.error("Error 级别的信息")
    logger.critical("Critical 级别的信息")
复制代码

运行结果如下

# 控制台输出:
2019-03-14 16:41:09 PM 11312:MainProcess- WARNING === Warning 级别的信息
2019-03-14 16:41:09 PM 11312:MainProcess- ERROR === Error 级别的信息
2019-03-14 16:41:09 PM 11312:MainProcess- CRITICAL === Critical 级别的信息

# test.log文件:
2019-03-14 16:41:09 PM 11312:MainProcess- INFO === Info 级别的信息
2019-03-14 16:41:09 PM 11312:MainProcess- WARNING === Warning 级别的信息
2019-03-14 16:41:09 PM 11312:MainProcess- ERROR === Error 级别的信息
2019-03-14 16:41:09 PM 11312:MainProcess- CRITICAL === Critical 级别的信息
复制代码

logging除了HandlerFormatter两个组件外还有,FilterLoggerAdapter组件,不过用得
不多,有兴趣的同学可以自行到官方文档进行查阅:docs.python.org/3/library/l…


如果本文对你有所帮助,欢迎
留言,点赞,转发
素质三连,谢谢😘~