Python学习笔记 - 常用模块

前言

Python官方提供了数量众多的模块,称为内置模块。本文主要讲解Python中一些在日常开发过程中常用的模块,至于其他的不常用模块可以自己在Python官网中查询Python官方的API文档。

Python 标准库最新版

一 math模块

Python官方提供math模块进行数学运算,如指数、对数、平方根和三角函数等运算。math模块中的函数只是整数和浮点数,不包括复数,复数计算需要使用 cmath 模块。

1.1 舍入函数

math模块提供的舍入函数有:math.ceil(a) 和 math.floor(a),math.ceil(a) 用来返回大于或等于 a 的最小整数,math.floor(a) 返回小于或等于 a 的最大整数。另外,Python还提供了一个内置函数 round(a),该函数用来对 a 进行四舍五入计算。

在Python Shell 中运行示例代码如下:

>>> math.ceil(1.4)
2
>>> math.floor(1.4)
1
>>> round(1.4)
1
>>> math.ceil(1.5)
2
>>> math.floor(1.5)
1
>>> round(1.5)
2
>>> math.ceil(1.6)
2
>>> math.floor(1.6)
1
>>> round(1.6)
2

1.2 幂和对数函数

math模块提供的幂和对数函数如下所示。

  • 对数运算:math.log(a[, base]) 返回以 base 为底的 a 的对数,省略底数 base,是 a 的自然数 e 的对数。

  • 平方根:math.sqrt(a) 返回a的平方根。

  • 幂运算:math.pow(a, b) 返回 a 的 b 次幂的值。

在 Python Shell 中运行示例代码如下:

>>> math.log(8, 2)
3.0
>>> math.pow(2, 3)
8.0
>>> math.log(8)
2.0794415416798357

1.3 三角函数

math模块中提供的三角函数有如下几种:

  • math.sin(a):返回弧度a的三角正弦。

  • math.cos(a):返回弧度a的三角余弦。

  • math.tan(a):返回弧度a的三角正切。

  • math.asin(a):返回弧度a的反正弦。

  • math.acos(a):返回弧度a的反余弦。

  • math.atan(a):返回弧度a的反正切。

上述函数中a参数是弧度。有时需要将弧度转换为角度,或将角度转换为弧度,math模块中提供了弧度和角度函数。

  • math.degree(a):将弧度a转换为角度。

  • math.radians(a):将角度a转换为弧度。

在 Python Shell 中运行示例代码如下:

>>> math.degrees(0.5 * math.pi)     # 调用degrees()函数将弧度转换为角度,其中math.pi是数学常量π
90.0
>>> math.radians(180 / math.pi)     # 调用radians()函数将角度转换为弧度
1.0
>>> a = math.radians(45 / math.pi)  # 将45度角转换为0.25弧度
>>> a
0.25
>>>
>>> math.sin(a)
0.24740395925452294
>>> math.asin(math.sin(a))
0.25
>>> math.asin(0.2474)
0.24999591371483254
>>> math.asin(0.24740395925452294)
0.25
>>>
>>> math.cos(a)
0.9689124217106447
>>> math.acos(0.9689124217106447)
0.2500000000000002
>>> math.acos(math.cos(a))
0.2500000000000002
>>>
>>> math.tan(a)
0.25534192122103627
>>> math.atan(math.tan(a))
0.25
>>> math.atan(0.25534192122103627)
0.25

二 random模块

random模块提供了一些生成随机数函数,相关函数见下述。

  • random.random():返回在范围大于或等于0.0,且小于1.0内的随机浮点数。

  • random.randrange(stop):返回在范围大于或等于0,且小于stop内,步长为1的随机整数。

  • random.randrange(start, stop[, step]):返回在范围大于或等于start,且小于stop内,步长为step的随机整数。

  • random.randint(a, b):返回在范围大于或等于a,且小于或等于b之间的随机整数。

示例代码如下:

# coding=utf-8
# 代码文件:random_demo.py
# random随机数模块使用示例

import random

# 0.0 <= x < 1.0 随机数
print('***** 0.0 <= x < 1.0 随机数 *****')
for i in range(0, 10):
    x = random.random() # 调用random()函数产生10个大于等于0.0小于1.0的随机浮点数
    print(x)

# 0 <= x < 10 随机数, 步长为1
print('***** 0 <= x < 10 随机数 *****')
for i in range(0, 10):
    x = random.randrange(10) # 调用randrange()函数产生10个大于等于0小于5的随机整数
    print(x, end = ' ')

print()
# 10<= x < 20 随机数, 步长为2
print('***** 10 <= x < 20 随机数 *****')
for i in range(0, 10):
    x = random.randrange(10, 20, 2) # 调用randrange()函数产生10个大于等于10小于20的随机整数,步长为2
    print(x, end = ' ')

print()
# 20 <= x <= 30 随机数
print('***** 20 <= x <= 30 随机数 *****')
for i in range(0, 10):
    x = random.randrange(20, 30) # 调用randrange()函数产生10个大于等于20或小于等于30的随机整数
    print(x, end = ' ')
print()

示例运行结果:

> python random_demo.py
***** 0.0 <= x < 1.0 随机数 *****
0.2600950020007613
0.5347034933571418
0.5197235867861837
0.2721707987274812
0.3731377067329801
0.23764883960218874
0.7946528038897872
0.22694072804616894
0.20968461237353753
0.5656559605330421
***** 0 <= x < 10 随机数 *****
4 7 6 3 9 1 2 2 2 8
***** 10 <= x < 20 随机数 *****
12 10 18 14 14 14 18 18 18 12
***** 20 <= x <= 30 随机数 *****
26 24 22 20 25 29 25 23 24 28

三 datetime模块

Python官方提供的日期和时间模块主要有time 和 datetime 模块。time 侧重于底层平台,模块中大多数函数会调用本地平台上的C链接库,因此有些函数运行结果,在不同平台上会有所不同。datetime模块对time模块进行了封装,提供了更高级的API,因此本章节重点介绍datetime模块的使用。

datetime模块中提供了以下几个类:

  • datetime类:包含时间和日期。

  • date类:只包含日期。

  • time类:只包含时间。

  • timedelta:计算时间跨度。

  • tzinfo类:时区信息。

3.1 datetime、date 和 time 类

datetime模块的核心类是 datetime、date 和 time 类。下面介绍如何创建这三种不同类的对象。

  1. datetime类

一个datetime对象可以表示日期和时间等信息,创建datetime对象可以使用如下构造方法:

datetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None)

其中的year、month和day三个参数是不能省略的;tzinfo 是时区参数,默认值是None,表示不指定时区;除了tzinfo外,其他的参数全部为合理范围内的整数。这些参数的取值范围如下表3-1所示,注意如果超出这个范围会抛出 ValueError 异常。

                                                                                               表3-1 参数取值范围

在Python Shell 中运行示例代码如下:

>>> import datetime                         # --1
>>> dt = datetime.datetime(2023, 2, 29)    # --2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: day is out of range for month
>>> dt = datetime.datetime(2023, 2, 28)
>>> dt
datetime.datetime(2023, 2, 28, 0, 0)
>>> dt = datetime.datetime(2023, 2, 28, 23, 60, 59, 10000) # --3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: minute must be in 0..59
>>> dt = datetime.datetime(2023, 2, 28, 23, 30, 59, 10000)
>>> dt
datetime.datetime(2023, 2, 28, 23, 30, 59, 10000)
>>>

在使用datetime模块时需要导入模块,见代码第1处。代码第2处试图创建datetime对象,由于天数29超出了范围,因此发生了ValueError异常。代码第3处也发生了ValueError异常,因为minute参数超出了取值范围。

除了通过构造方法创建并初始化datetime对象,还可以通过datetime类提供的一些类方法获得datetime对象,这些类方法有以下几种:

  • datetime.today():返回当前本地日期和时间。

  • datetime.now(tz=None):返回本地当前的日期和时间,如果参数tz为None或未指定,则等同于today()。

  • datetime.utcnow():返回当前UTC日期和时间。

  • datetime.fromtimestamp(timestamp, tz=None):返回与UNIX时间戳对应的本地日期和时间。

  • datetime.utcfromtimestamp(timestamp):返回与UNIX时间戳对应的UTC日期和时间。

UTC( Universal Time Coordinated) 即协调世界时间,它以原子时为基础,是时刻上尽量接近世界时的一种时间计量系统。UTC比GMT更加精准,它的出现满足了现在社会对于精确计时的需要。GMT即格林威治标准时间,格林威治标准时间是19世纪中叶大英帝国的基准时间,同时也是世界基准时间。

在Python SHell 中运行示例代码如下:

>>> import datetime
>>> datetime.datetime.today()                          # --1
datetime.datetime(2023, 2, 1, 0, 13, 26, 30545)
>>> datetime.datetime.now()                            # --2
datetime.datetime(2023, 2, 1, 0, 13, 55, 408356)
>>> datetime.datetime.utcnow()                         # --3
datetime.datetime(2023, 1, 31, 16, 14, 22, 770392)
>>> datetime.datetime.fromtimestamp(999999999.999)     # --4
datetime.datetime(2001, 9, 9, 9, 46, 39, 999000)
>>> datetime.datetime.utcfromtimestamp(999999999.999)  # --5
datetime.datetime(2001, 9, 9, 1, 46, 39, 999000)
>>>

从上述代码运行结果可见,如果没有指定时区,datetime.now() 和 datetime.today() 是相同的,见代码第1处和第2处。代码第3处中 datetime.utcnow() 与 datetime.today() 相比晚了8个小时,这是因为 datetime.today() 获取的是本地时间,而笔者所在地是北京时间,即东八区,本地时间比UTC时间早8小时。代码第4处和第5处通过时间戳创建datetime对象,从结果可见,同样的时间戳 datetime.fromtimestamp() 比 datetime.utcfromtimestamp() 也是早8个小时。

注意1》在Python语言中时间戳单位是“秒”,所以它会有小数部分。而其他语言如Java单位是“毫秒”,当跨平台计算时间时需要注意这个差别。
注意2》时间戳的秒数是从1970年1月1日 00:00:00 以来到当前时刻的总秒数。
2. date类

一个date对象可以表示日期等信息,创建date对象可以使用如下构造方法:

datetime.date(year, month, day)

其中的year、month和day三个参数是不能省略的,参数应为合理范围内的整数,这些参数的取值范围可以参考上表3-1,如果超出这个范围会抛出异常ValueError。

在Python Shell 中运行示例代码如下:

>>> import datetime
>>> d = datetime.date(2023, 2, 29)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: day is out of range for month
>>> d = datetime.date(2023, 2, 28)
>>> d
datetime.date(2023, 2, 28)
>>>

>>> import datetime
>>> datetime.date.today()
datetime.date(2023, 2, 1)
>>> datetime.date.fromtimestamp(999999999.999)
datetime.date(2001, 9, 9)
>>>
3. time类

一个time对象可以表示一天中时间信息,创建time对象可以使用如下构造方法:

datetime.time(hour=0, minute=0, second=0, microsecond=0, tzinfo=None)

所有参数都是可选的,除tzinfo外,其他参数应为合理范围内的整数,这些参数的取值范围可以参考上表3-1,如果超出这个范围会抛出异常。

在Python Shell 中运行示例代码如下:

>>> import datetime
>>> datetime.time(24, 59, 59, 1999)    # --1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: hour must be in 0..23
>>> datetime.time(23, 59, 59, 1999)
datetime.time(23, 59, 59, 1999)
>>>

在使用time时需要导入datetime模块。代码第1处试图创建time对象,由于一天时间不能超过24,因此发生ValueError异常。

3.2 日期时间计算

如果想知道10天之后是哪一天,或想知道2023年2月1日前5周是哪一天,就需要使用timedelta类了,timedelta对象用于计算datetime、date 和 time对象时间间隔。

timedelta类构造方法如下:

datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)

所有参数都是可选的,参数可以为整数或浮点数,可以为正数或负数。在timedelta内部只保存days(天)、seconds(秒)和 microseconds(微秒)变量,所以其他参数milliseconds(毫秒)、minutes(分钟)和weeks(周)都应换算为days、seconds和microseconds这三个参数。

在Python Shell 中运行示例代码如下:

>>> import datetime
>>> datetime.date.today()
datetime.date(2023, 2, 4)
>>> d = datetime.date.today()              # 获取当前本地日期
>>> delta = datetime.timedelta(10)         # 创建间隔时间为10天的timedelta对象
>>> d += delta                             # 当前日期+10天
>>> d
datetime.date(2023, 2, 14)
>>> d = datetime.date(2023, 1, 1)          # 创建2023年1月1日的日期对象
>>> delta = datetime.timedelta(weeks = 4)  # 创建时间间隔为4周的timedelta对象
>>> d += delta                             # 表示d后4周的日期
>>> d
datetime.date(2023, 1, 29)

本例中只演示了日期的计算,使用timedelta对象可以精确到微秒,这里不再赘述。

3.3 日期时间格式化和解析

无论是日期还是时间,当显示在界面上时,都需要进行格式化输出,使它能够符合当地人查看日期和时间的习惯。与日期时间格式化输出相反的操作为日期时间的解析,当用户使用输入程序界面输入日期时,计算机能够读入的是字符串,经过解析这些字符串获得日期时间对象。

Python中日期时间格式化使用 strftime() 方法,datetime、date 和 time 这三个类中都有一个实例方法 strftime(format);而日期时间解析使用datetime.strptime(date_string, format) 类方法,date和time没有strptime()方法。方法strftime()和strptime()中都有一个格式化参数format,用来控制日期时间的格式,如下表3-2所示,是常用的日期和时间格式控制符。

                                                             表3-2 常用的日期和时间格式控制符

《提示》上表3-2中的数字都是十进制数字。控制符会因不同平台有所区别,这是因为Python调用了本地平台C库的strftime()函数而进行了日期和时间格式化。事实上这些控制符是1989版C语言控制符。表3-2只是列出了常用的控制符,更多的控制符可参考如下链接:
strftime() 和 strptime() 的行为

在Python Shell 中运行示例代码如下:

>>> import datetime
>>> d = datetime.datetime.today()    # 获取当前本地日期时间对象
>>> d.strftime("%Y-%m-%d %H:%M:%S")  # 对当前日期时间对象d进行字符串格式化,d包含日期和时间信息。如果只关系其中部分信息,在格式化时可以指定部分控制符
'2023-02-04 14:47:16'
>>> d.strftime("%Y-%m-%d")  # 对日期时间对象d进行格式化时只指定部分控制符,这里只设置了年月日
'2023-02-04'
>>> 
>>> str_date = '2023-02-29 14:49:50'
>>> date = datetime.datetime.strptime(str_date, '%Y-%m-%d %H:%M:%S') # 试图解析日期时间字符串str_date,但是2023年2月没有29日,所以解析过程会抛出ValueError异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\Program Files\Python\Lib\_strptime.py", line 568, in _strptime_datetime
    tt, fraction, gmtoff_fraction = _strptime(data_string, format)
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Program Files\Python\Lib\_strptime.py", line 534, in _strptime
    julian = datetime_date(year, month, day).toordinal() - \
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: day is out of range for month
>>> str_date = '2023-02-28 14:49:50'
>>> date = datetime.datetime.strptime(str_date, '%Y-%m-%d %H:%M:%S')
>>> date
datetime.datetime(2023, 2, 28, 14, 49, 50)
>>>
>>> date = datetime.datetime.strptime(str_date, '%Y-%m-%d') # 设置的控制符只有年月日,而要解析的字符串是有时分秒的,所以会抛出ValueError异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\Program Files\Python\Lib\_strptime.py", line 568, in _strptime_datetime
    tt, fraction, gmtoff_fraction = _strptime(data_string, format)
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Program Files\Python\Lib\_strptime.py", line 352, in _strptime
    raise ValueError("unconverted data remains: %s" %
ValueError: unconverted data remains:  14:49:50
>>>

3.4 时区

datetime和time对象只是单纯地表示本地的日期和时间,没有时区信息。如果想带有时区信息,可以使用timezone类,它是tzinfo的子类,提供了UTC偏移时区的实现。timezone类构造方法如下:

datetime.timezone(offset, name=None)

其中offset是UTC偏移量,+8是东八区,北京在此时区。-5是西五区,纽约在此时区,0是零时区,伦敦在此时区。name参数是时区名称,如Asia/Beijing,可以省略不写。

在Python Shell 中运行示例代码如下:

>>> from datetime import datetime, timezone, timedelta                     # --1
>>> utc_dt = datetime(2023, 2, 4, 15, 6, 59, tzinfo = timezone.utc)       # --2 相当于 timezone(timedelta(0))
datetime.datetime(2023, 2, 4, 15, 6, 59, tzinfo=datetime.timezone.utc)
>>> utc_dt.strftime("%Y-%m-%d %H:%M:%S %Z")                                # --3
'2023-02-04 15:06:59 UTC'
>>> utc_dt.strftime("%Y-%m-%d %H:%M:%S %z")                                # --4
'2023-02-04 15:06:59 +0000'
>>> 
>>> bj_tz = timezone(offset = timedelta(hours = 8), name = 'Asia/Beijing') # --5
>>> bj_tz
datetime.timezone(datetime.timedelta(seconds=28800), 'Asia/Beijing')
>>> 
>>> bj_dt = utc_dt.astimezone(bj_tz)                                       # --6
>>> bj_dt
datetime.datetime(2023, 2, 4, 23, 6, 59, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800), 'Asia/Beijing'))
>>> bj_dt.strftime('%Y-%m-%d %H:%M:%S %Z')
'2023-02-04 23:06:59 Asia/Beijing'
>>> bj_dt.strftime('%Y-%m-%d %H:%M:%S %z')
'2023-02-04 23:06:59 +0800'
>>>
>>> bj_tz = timezone(timedelta(hours = 8))                                 # --7
>>> bj_dt = utc_dt.astimezone(bj_tz)
>>> bj_dt.strftime('%Y-%m-%d %H:%M:%S %z')
'2023-02-04 23:06:59 +0800'
>>>

(1)上述代码第1处采用from...import...语句导入datetime模块,并明确指定导入datetime、timezone和timedelta类,这样在使用时就不必在类名的前面再加上datetime模块名了,使用起来比较简洁。如果想导入所有的类可以使用:from datetime import * 语句。

(2)代码第2处创建了datetime对象utc_dt,tzinfo=timezone.utc表示设置UTC时区,相当于timezone(timedelta(0))。

(3)代码第3处和第4处分别格式化输出utc_dt,它们都分别带有时区控制符:%Z、%z。

(4)代码第5处创建了timezone对象bj_tz,offset=timedelta(hours=8) 表示设置社区偏移量为东八区,即北京时间。name=Asia/Beijing是时区名,也可以省略不写,见代码第7处。完成时区创建还需要设置具体的datetime对象。

(5)代码第6处utc_dt.astimezone(bj_tz) 是调整时区,返回值bj_dt就变成北京时间了。

四 logging日志模块

在程序开发过程中,有时需要输出一些调试信息;在程序发布后,有时需要一些程序的运行信息;在程序发生错误时需要输出一些错误信息。这些可以通过在程序中加入日志输出实现。大部分开发人员会使用print()函数进行日志输出,但是print()函数要想同时输出日志信息和时间、所在函数、所在线程等内容是比较困难的。让print()函数输出日志到文件也是非常困难的。而且print()函数不能分级输出日志,例如一些信息是在调试阶段输出,在程序发布后,不需要输出这些信息,这就是分级输出,print()函数做不到这一点。

综上所述,要想满足复杂的日志输出需求,不能使用print()函数,可以使用logging模块,它是Python的内置模块。

4.1 日志级别

logging模块提供5种常用级别,如下表4-3所示。这5种级别从上到下由低到高。如果设置了DEBUG级别,debug()函数和其他级别的函数的日志信息都会输出;如果设置了ERROR级别,error()和critical()函数的日志信息会输出。

                                                                              表4-3  日志级别

示例代码如下:

# coding=utf-8
# 代码文件: logging_level.py
# 使用logging模块输出不同日志级别的日志信息

import logging
logging.basicConfig(level = logging.ERROR) # --1

logging.debug('这是 Debug 级别信息')
logging.info('这是 INFO 级别信息')
logging.warning('这是 WARNING 级别信息')
logging.error('这是 ERROR 级别信息')
logging.critical('这是 CRITICAL 级别信息')

运行结果:

>python logging_level.py
ERROR:root:这是 ERROR 级别信息
CRITICAL:root:这是 CRITICAL 级别信息

上述代码第1处对日志进行基本配置,level = logging.ERROR 中设置日志级别为ERROR。如果改变日志级别为DEBUG,所有日志函数信息都能输出,输出的结果是:

>python logging_level.py
DEBUG:root:这是 Debug 级别信息
INFO:root:这是 INFO 级别信息
WARNING:root:这是 WARNING 级别信息
ERROR:root:这是 ERROR 级别信息
CRITICAL:root:这是 CRITICAL 级别信息

在输出的日志信息中会有root关键字,这说明进行日志输出的对象是root日志器(logger)。也可以使用getLogger()函数创建自己的日志器对象,代码如下:

logger = logging.getLogger(__name__)

getLogger()函数的参数是一个字符串,本例中 __name__ 是当前模块名。使用自定义日志器的示例代码如下:

# coding=utf-8
# 代码文件: logging_level2.py
# 使用logging模块输出不同日志级别的日志信息

import logging
logging.basicConfig(level = logging.DEBUG)

logger = logging.getLogger(__name__)  # --1:创建日志器对象

logger.debug('这是 Debug 级别信息')   # --2
logger.info('这是 INFO 级别信息')
logger.warning('这是 WARNING 级别信息')
logger.error('这是 ERROR 级别信息')
logger.critical('这是 CRITICAL 级别信息')

运行结果如下:

>python logging_level2.py
DEBUG:__main__:这是 Debug 级别信息
INFO:__main__:这是 INFO 级别信息
WARNING:__main__:这是 WARNING 级别信息
ERROR:__main__:这是 ERROR 级别信息
CRITICAL:__main__:这是 CRITICAL 级别信息

上述代码第1处是自定义一个日志器logger对象,有了日志器对象就可以通过日志器对象调用日志函数了,见代码第2处。

4.2 日志信息格式化

可以根据自己的需要设置日志信息的格式化布局。常用的格式化参数如下表4-4所示。

                                                                       表4-4  日志信息格式化

示例代码如下:

# coding=utf-8
# 代码文件: logging_format.py
# 根据需要设置日志信息的格式化布局

import logging
logging.basicConfig(level = logging.INFO, format='%(asctime)s - %(threadName)s - %(name)s - %(funcName)s - %(levelname)s'
                                                 ' - %(message)s')  # --1

logger = logging.getLogger(__name__)  # 创建日志器对象

logger.debug('这是 Debug 级别信息')
logger.info('这是 INFO 级别信息')
logger.warning('这是 WARNING 级别信息')
logger.error('这是 ERROR 级别信息')
logger.critical('这是 CRITICAL 级别信息')

def funlog():
    logger.info('进入 funlog 函数')

logger.info('调用 funlog 函数')
funlog()

运行结果:

>python logging_format.py
2023-02-07 01:45:17,756 - MainThread - __main__ - <module> - INFO - 这是 INFO 级别信息
2023-02-07 01:45:17,756 - MainThread - __main__ - <module> - WARNING - 这是 WARNING 级别信息
2023-02-07 01:45:17,756 - MainThread - __main__ - <module> - ERROR - 这是 ERROR 级别信息
2023-02-07 01:45:17,756 - MainThread - __main__ - <module> - CRITICAL - 这是 CRITICAL 级别信息
2023-02-07 01:45:17,756 - MainThread - __main__ - <module> - INFO - 调用 funlog 函数
2023-02-07 01:45:17,756 - MainThread - __main__ - funlog - INFO - 进入 funlog 函数

上述代码第1处是通过basicConfig()函数的format参数设置日志格式化信息。从输出结果可见,%(name)s格式化输出日志器名称为:__main__;%(funcName)s 格式化输出函数名为:MainThread。

4.3 日志重定向

日志信息默认是输出到控制台的,也可以将日志信息输出到日志文件中,甚至可以输出到网络中的其他计算机。

输出到日志文件中的示例代码如下:

# coding=utf-8
# 代码文件: logging_redirect.py
# 将日志重定向到日志文件中

import logging
logging.basicConfig(level = logging.INFO, format='%(asctime)s - %(threadName)s - %(name)s - %(funcName)s - %(levelname)s'
                                                 ' - %(message)s', filename = 'test.log')  # --1

logger = logging.getLogger(__name__)  # 创建日志器对象

logger.debug('这是 Debug 级别信息')
logger.info('这是 INFO 级别信息')
logger.warning('这是 WARNING 级别信息')
logger.error('这是 ERROR 级别信息')
logger.critical('这是 CRITICAL 级别信息')

def funlog():
    logger.info('进入 funlog 函数')

logger.info('调用 funlog 函数')
funlog()

上述代码第1处basicConfig()函数的参数 filename = 'test.log',是设置日志文件名,也包括路径,但是需要注意的是,路径中的目录名是存在的。程序运行时日志不会在控制台输出,而是写入当前目录中的 test.log 文件,默认情况下日志信息是不断追加到文件中的。

test.log日志文件内容如下:

2023-02-04 18:10:18,476 - MainThread - __main__ - <module> - INFO - 这是 INFO 级别信息
2023-02-04 18:10:18,476 - MainThread - __main__ - <module> - WARNING - 这是 WARNING 级别信息
2023-02-04 18:10:18,476 - MainThread - __main__ - <module> - ERROR - 这是 ERROR 级别信息
2023-02-04 18:10:18,476 - MainThread - __main__ - <module> - CRITICAL - 这是 CRITICAL 级别信息
2023-02-04 18:10:18,476 - MainThread - __main__ - <module> - INFO - 调用 funlog 函数
2023-02-04 18:10:18,476 - MainThread - __main__ - funlog - INFO - 进入 funlog 函数

4.4 使用配置文件

上面的日志示例中,日志信息的配置都是在basicConfig()函数中进行的,这样就不是很方便,每次修改日志配置时都要修改程序代码。特别是在程序发布后,系统维护人员要修改代码,可能会引起严重的责任问题。此时,可以使用配置文件,配置信息可以从配置文件中读取。

从配置文件中读取的示例代码如下:

# coding=utf-8
# 代码文件: logging_config.py
# 使用日志配置文件来配置日志输出的格式

import logging
import logging.config

logging.config.fileConfig("logger.conf") # --1

logger = logging.getLogger('logger1')    # --2

logger.debug('这是 Debug 级别信息')
logger.info('这是 INFO 级别信息')
logger.warning('这是 WARNING 级别信息')
logger.error('这是 ERROR 级别信息')
logger.critical('这是 CRITICAL 级别信息')

def funlog():
    logger.info('进入 funlog 函数')

logger.info('调用 funlog 函数')
funlog()

代码第1处是指定配置信息是从配置文件logger.conf中读取的,代码第2处是从配置文件中读取logger1配置信息创建日志器。

配置文件logger.conf内容如下:

[loggers]               # 配置日志器 --1
keys=root,simpleExample # 日志器包含了root和simpleExample

[logger_root] # 配置根日志器
level=DEBUG
handlers=consoleHandler # 日志器对应的处理器

[logger_simpleExample] # 配置simpleExample日志器
level=DEBUG
handlers=fileHandler   # 日志器对应的处理器
qualname=logger1       # 设置日志器名称

[handlers]             # 配置处理器 --2
keys=consoleHandler,fileHandler # 包含了两个处理器

[handler_consoleHandler] # 配置 consoleHandler 处理器
class=StreamHandler      # --3
level=DEBUG
formatter=simpleFormatter # --4
args=(sys.stdout,)        # 输出流是终端控制台 --5

[handler_fileHandler]  # 配置 fileHandler 处理器
class=FileHandler      # --6
level=DEBUG
formatter=simpleFormatter
args=('test2.log', 'a')  # 指定输出日志文件 --7

[formatters]          # 配置格式化器 --8
keys=simpleFormatter  # 日志器包含 simpleFormatter --9

[formatter_simpleFormatter] # 配置 simpleFormatter 格式化器 --10
format=%(asctime)s-%(levelname)s-%(message)s

在配置文件中需要配置主要项目是日志器、处理器和格式化器,见代码第1处、第2处和第8处。其中处理器就是指定日志信息输出到哪里,包括控制台、文件和网络等;格式化器就是将日志信息进行格式化。它们之间的依赖关系是,日志器依赖于处理器,处理器依赖于格式化器。

这三个配置又可以分为多个子配置信息,例如日志器可以分为root和simpleExample两个,处理器有consoleHandler 和 fileHandler 两个,格式化器只有simpleFormatter一个。

下面重点介绍一下处理器。代码第3处设置处理器类是StreamHandler,即输入输出流处理器,包括控制台、网络等。代码第4处设置该处理器采用的格式化器。代码第5处设置输出流是控制台。代码第6处是设置处理器类是FileHandler,即文件处理器。代码第7处是指定输出文件为test2.log,并以追加的方式打开文件。

logging_config.py 代码中指定的日志器名是logger1,也就是配置文件中simpleExample日志器,它依赖的处理器是fileHandler,fileHandler处理器依赖的配置格式化器是simpleFormatter。

参考

《Python从小白到大牛(第1版-2018).pdf》第13章 - 常用模块

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python学习笔记》是由皮大庆编写的一本关于Python语言学习的教材。在这本书中,作者详细介绍了Python语言的基础知识、语法规则以及常用的编程技巧。 首先,作者简要介绍了Python语言的特点和优势。他提到,Python是一种易于学习和使用的编程语言,受到了广大程序员的喜爱。Python具有简洁、清晰的语法结构,使得代码可读性极高,同时也提供了丰富的库和模块,能够快速实现各种功能。 接着,作者详细讲解了Python的基本语法。他从变量、数据类型、运算符等基础知识开始,逐步介绍了条件语句、循环控制、函数、模块等高级概念。同时,作者通过大量的示例代码和实践案例,帮助读者加深对Python编程的理解和应用。 在书中,作者还特别强调了编写规范和良好的编程习惯。他从命名规范、注释风格、代码缩进等方面指导读者如何写出清晰、可读性强的Python代码。作者认为,良好的编程习惯对于提高代码质量和提高工作效率非常重要。 此外,作者还介绍了Python常用库和模块。他提到了一些常用的库,如Numpy、Pandas、Matplotlib等。这些库在数据处理、科学计算、可视化等领域有广泛的应用,帮助读者更好地解决实际问题。 总的来说,《Python学习笔记》是一本非常实用和全面的Python学习教材。通过学习这本书,读者可以系统地学习和掌握Python编程的基础知识和高级应用技巧,为以后的编程学习和工作打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值