time
模块在Python中,通常有这三种方式来表示时间:时间戳、元组(struct_time)、格式化的时间字符串:
type(time.time())
,返回的是float类型。# <1> 时间戳
>>> import time
>>> time.time() #--------------返回当前时间的时间戳
1612009211.2890282
# <2> 时间字符串
>>> time.strftime("%Y-%m-%d %X")
'2021-01-30 20:20:34'
# <3> 时间元组
>>> time.localtime()
time.struct_time(tm_year=2021, tm_mon=1, tm_mday=30,
tm_hour=20, tm_min=20, tm_sec=53,
tm_wday=5, tm_yday=30, tm_isdst=0
)
小结:时间戳是计算机能够识别的时间;时间字符串是人能够看懂的时间;元组则是用来操作时间的
几种时间形式的转换:
#一 时间戳<---->结构化时间: localtime/gmtime mktime
>>> time.localtime(3600*24)
>>> time.gmtime(3600*24)
>>> time.mktime(time.localtime())
#字符串时间<---->结构化时间: strftime/strptime
>>> time.strftime("%Y-%m-%d %X", time.localtime())
>>> time.strptime("2017-03-16","%Y-%m-%d")
>>> time.asctime(time.localtime(312343423))
'Sun Nov 25 10:03:43 1979'
>>> time.ctime(312343423)
'Sun Nov 25 10:03:43 1979'
# sleep(secs)
# 线程推迟指定的时间运行,单位为秒。
import time
# 时间戳格式 timestamp 机器易读
print(time.time()) # 当前的时间戳
# 1598165164.115248
# 1970-01-01 00:00:00
# 1970-01-01 08:00:00
# 结构化格式 structtime 在时间戳和格式化时间之间做转换
print(time.localtime()) # 当前的结构化时间
# time.struct_time(tm_year=2020, tm_mon=8,
# tm_mday=23, tm_hour=14, tm_min=48, tm_sec=19, tm_wday=6, tm_yday=236, tm_isdst=0)
# 格式化格式 formattime 人类易读
print(time.strftime('%Y-%m-%d %H:%M:%S')) # 当前的格式化时间
# 2020-08-23 14:51:02
ts = 1500000000
struct_t = time.localtime(ts)
print(struct_t) # 165 days, 5:07:54
strf_time = time.strftime('%Y-%m-%d %H:%M:%S', struct_t)
# year month day hour minute second
print(strf_time)
# strf_time = time.strftime('%Y/%m/%d %H:%M:%S',struct_t)\
# # year month day hour minute second
# print(strf_time)
strf_t = '2018-08-08 08:08:08'
struct_t = time.strptime('2018-08-08 20:08:08','%Y-%m-%d %H:%M:%S')
print(struct_t)
ts = time.mktime(struct_t)
print(ts) # 1533730088.0
datetime
模块- 获取当前日期和时间
from datetime import datetime
print(datetime.now())
'''
结果:2018-12-04 21:07:48.734886
'''
注意:datetime是模块,datetime模块还包含一个datetime的类,通过from datetime import datetime导入的才是datetime这个类。
- 如果仅导入import datetime,则必须引用全名datetime.datetime。
datetime.now()返回当前日期和时间,其类型是datetime。
获取指定日期和时间
要指定某个日期和时间,我们直接用参数构造一个datetime:
from datetime import datetime
dt = datetime(2018,5,20,13,14)
print(dt)
'''
结果:2018-05-20 13:14:00
'''
datetime转换为timestamp
from datetime import datetime
dt = datetime.now()
new_timestamp = dt.timestamp()
print(new_timestamp)
'''
结果:1543931750.415896
'''
timestamp转换为datetime
import time
from datetime import datetime
new_timestamp = time.time()
print(datetime.fromtimestamp(new_timestamp))
str转换为datetime
很多时候,用户输入的日期和时间是字符串,要处理日期和时间,首先必须把str转换为datetime。转换方法是通过datetime.strptime()实现,需要一个日期和时间的格式化字符串:
from datetime import datetime
t = datetime.strptime('2018-4-1 00:00','%Y-%m-%d %H:%M')
print(t)
'''
结果: 2018-04-01 00:00:00
'''
datetime转换为str
如果已经有了datetime对象,要把它格式化为字符串显示给用户,就需要转换为str,转换方法是通过strftime()实现的,同样需要一个日期和时间的格式化字符串:
from datetime import datetime
now = datetime.now()
print(now.strftime('%a, %b %d %H:%M'))
Mon, May 05 16:28
datetime加减
对日期和时间进行加减实际上就是把datetime往后或往前计算,得到新的datetime。加减可以直接用+和-运算符,不过需要导入timedelta这个类:
from datetime import datetime, timedelta
now = datetime.now()
now
datetime.datetime(2015, 5, 18, 16, 57, 3, 540997)
now + timedelta(hours=10)
datetime.datetime(2015, 5, 19, 2, 57, 3, 540997)
now - timedelta(days=1)
datetime.datetime(2015, 5, 17, 16, 57, 3, 540997)
now + timedelta(days=2, hours=12)
datetime.datetime(2015, 5, 21, 4, 57, 3, 540997)
可见,使用timedelta你可以很容易地算出前几天和后几天的时刻。
小结
datetime表示的时间需要时区信息才能确定一个特定的时间,否则只能视为本地时间。
如果要存储datetime,最佳方法是将其转换为timestamp再存储,因为timestamp的值与时区完全无关。
from datetime import datetime
d = datetime.now()
# d已经是datetime类型的数据,时间类型数据
print(d.strftime('%Y-%m-%d %a %A %b %B %H:%M:%S')) # 当前时间转换成字符串格式化时间
print(d.strftime('%c')) # 当前时间转换成字符串格式化时间
print(type(d.strftime('%Y-%m-%d %H:%M:%S '))) # str 查看格式化时间的数据类型位str
print(datetime.strptime('2018-08-08 08:08:08', '%Y-%m-%d %H:%M:%S')) # 把字符串时间转换成datetime类型
print(type(datetime.strptime('2018-08-08 08:08:08', '%Y-%m-%d %H:%M:%S'))) # 查看datetime时间的数据类型 datetime
print(d.day) # 查看天(月份中的天)
print(d.date()) # 查看年月日
print(d.time()) # 查看时分秒data
print(d.hour) # 查看小时数
d1 = datetime(2020, 8, 23, 15, 28, 12)
d2 = datetime(2020, 3, 11, 10, 20, 18)
print(d1-d2) # 求两个时间之间的差
In [10]: import datetime
In [11]: datetime.datetime.now().strftime('%Y-%m-%d %X')
Out[11]: '2021-01-30 21:43:20'
import datetime
# 返回当前时间的两分钟前
two_minutes_before = (datetime.datetime.now() + datetime.timedelta(minutes=-2)).strftime('%Y-%m-%d %H:%M:%S')
print(two_minutes_before)
# 返回当前时间的两小时前
two_hours_before = (datetime.datetime.now() + datetime.timedelta(hours=-2)).strftime('%Y-%m-%d %H:%M:%S')
print(two_hours_before)
random
模块>>> import random
>>> random.random() # 大于0且小于1之间的小数
0.7664338663654585
>>> random.randint(1,5) # 大于等于1且小于等于5之间的整数
2
>>> random.randrange(1,3) # 大于等于1且小于3之间的整数
1
>>> random.choice([1,'23',[4,5]]) # #1或者23或者[4,5]
1
>>> random.sample([1,'23',[4,5]],2) # #列表元素任意2个组合
[[4, 5], '23']
>>> random.uniform(1,3) #大于1小于3的小数
1.6270147180533838
>>> item=[1,3,5,7,9]
>>> random.shuffle(item) # 打乱次序
>>> item
[5, 1, 3, 7, 9]
>>> random.shuffle(item)
>>> item
[5, 9, 7, 1, 3]
案例:生成随机验证码
import random
def v_code():
code = ''
for i in range(5):
num=random.randint(0,9)
alf=chr(random.randint(65,90))
add=random.choice([num,alf])
code="".join([code,str(add)])
return code
print(v_code())
os
模块os模块
是与操作系统交互的一个接口
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd
os.curdir 返回当前目录: ('.')
os.pardir 获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2') 可生成多层递归目录
os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() 删除一个文件
os.rename("oldname","newname") 重命名文件/目录
os.stat('path/filename') 获取文件/目录信息
os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") 运行shell命令,直接显示
os.environ 获取系统环境变量
os.path.abspath(path) 返回path规范化的绝对路径
os.path.split(path) 将path分割成目录和文件名二元组返回
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path) 如果path是绝对路径,返回True
os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path) 返回path所指向的文件或者目录的最后访问时间
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小
import os
# os 和操作系统打交道
# 获取当前文件所在目录的父级目录
# BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# print(BASE_DIR)
# F:\文档\code\pythonCode\pro
# os.mkdir('test') 新建文件夹
# os.rmdir('test') 删除文件夹
# 查看目录下所有目录
ret = os.listdir(r'F:\文档\code\pythonCode\pro')
print(ret)
# ['.idea', 'venv', '常用模块']
# 查询文件信息
print(os.stat(r'F:\文档\code\pythonCode\pro\常用模块\test_os.py'))
# os.stat_result(st_mode=33206, st_ino=844424930391798, st_dev=227480759, st_nlink=1, st_uid=0, st_gid=0, st_size=1710, st_atime=1612011212, st_mtime=1612011212, st_ctime=1612010671)
# 在python中想使用shell命令的时候
os.system('dir') # 没有返回值
ret = os.popen('dir') # 有返回值
for line in ret:
print(line.strip())
print(os.getcwd()) # 获取当前所在的工作目录
os.chdir(r'F:\文档\code\pythonCode\pro') # 修改当前所在的工作目录
print(os.getcwd())
# 帮助我们完成最后一级的目录完成切分和返回
ret = os.path.split(r'F:\文档\code\pythonCode\pro\常用模块')
print(ret) # ('F:\\文档\\code\\pythonCode\\pro', '常用模块')
# 获取当前文件所在目录
print(os.path.dirname(r'F:\文档\code\pythonCode\pro\常用模块\test_os.py'))
# 获取当前文件名
filename = os.path.basename(r'F:\文档\code\pythonCode\pro\常用模块\test_os.py')
print(filename)
# 拼接路径:目录和文件拼接
print(os.path.join(r'F:\文档\code\pythonCode\pro\常用模块', 'test_os.py'))
# 获取当前文件的绝对路径
print(os.path.abspath('file')) # 无论写一个什么文件名,会把当前的工作目录拼上你写入的参数组成一个绝对路径
# F:\文档\code\pythonCode\pro\常用模块\file
# 判断文件是否存在
ret = os.path.exists(r'F:\文档\code\pythonCode\pro\常用模块\test_os.py')
print(ret)
# 判断是文件还是文件夹
ret = os.path.isdir(r'F:\文档\code\pythonCode\pro\常用模块')
print(ret) # True
ret = os.path.isfile(r'F:\文档\code\pythonCode\pro\常用模块')
print(ret) # False
# 只能计算单文件的大小,计算文件夹的大小也计算不准
ret = os.path.getsize(r'F:\文档\code\pythonCode\pro\常用模块')
print(ret) # 4096
sys
模块sys模块是与解释器交互的一个模块
sys.argv 命令行参数List,第一个元素是程序本身路径
sys.exit(n) 退出程序,正常退出时exit(0)
sys.version 获取Python解释程序的版本信息
sys.maxint 最大的Int值
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称
import sys
# sys 和python解释器打交道
# sys.exit() # === exit() 表示结束当前的python程序的运行
# 判断项目程序python版本依赖,不符合则停止运行
if sys.version.startswith('3'):
print('本程序仅支持pythone2.x版本运行')
print(f'当前python版本为:{sys.version}')
sys.exit()
# 查看python版本
print(sys.version) # 3.6.5
# 查看当前系统版本
print(sys.platform) # win32
# 当我们导入的模块的时候,是从前到后读取sys.path中的路径,并依次到路径下寻找对应位文件\文件夹.
# sys.path
# 在执行一个文件的时候,可以传递一些参数给这个文件 sys.argv
# python xxxxx.py replace 文件路径 a b
# python xxxxx.py cp 文件路径 目标文件路径下目标文件名
# _,action,file_path,old_str,new_str = sys.argv
# print(action,file_path,old_str,new_str)
# if action == 'replace':
# pass
logging
模块日志是一种可以追踪某些软件运行时所发生事件的方法。软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情。一个事件可以用一个可包含可选变量数据的消息来描述。此外,事件也有重要性的概念,这个重要性也可以被称为严重性级别(level)。
在软件开发阶段或部署开发环境时,为了尽可能详细的查看应用程序的运行状态来保证上线后的稳定性,我们可能需要把该应用程序所有的运行日志全部记录下来进行分析,这是非常耗费机器性能的。当应用程序正式发布或在生产环境部署应用程序时,我们通常只需要记录应用程序的异常信息、错误信息等,这样既可以减小服务器的I/O压力,也可以避免我们在排查故障时被淹没在日志的海洋里。那么,怎样才能在不改动应用程序代码的情况下实现在不同的环境记录不同详细程度的日志呢?这就是日志等级的作用了,我们通过配置文件指定我们需要的日志等级就可以了。
不同的应用程序所定义的日志等级可能会有所差别,分的详细点的会包含以下几个等级:
级别 | 何时使用 |
---|---|
DEBUG | 详细信息,典型地调试问题时会感兴趣。 详细的debug信息。 |
INFO | 证明事情按预期工作。 关键事件。 |
WARNING | 表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。 |
ERROR | 由于更严重的问题,软件已不能执行一些功能了。 一般错误消息。 |
CRITICAL | 严重错误,表明软件已不能继续运行了。 |
NOTICE | 不是错误,但是可能需要处理。普通但是重要的事件。 |
ALERT | 需要立即修复,例如系统数据库损坏。 |
EMERGENCY | 紧急情况,系统不可用(例如系统崩溃),一般会通知所有用户。 |
一条日志信息对应的是一个事件的发生,而一个事件通常需要包括以下几个内容:
事件发生时间
事件发生位置
事件的严重程度–日志级别
事件内容
上面这些都是一条日志记录中可能包含的字段信息,当然还可以包括一些其他信息,如进程ID、进程名称、线程ID、线程名称等。日志格式就是用来定义一条日志记录中包含那些字段的,且日志格式通常都是可以自定义的。
logging模块的使用
logging模块的日志级别:
logging模块默认定义了以下几个日志等级,它允许开发人员自定义其他日志级别,但是这是不被推荐的,尤其是在开发供别人使用的库时,因为这会导致日志级别的混乱。
日志等级(level) | 描述 |
---|---|
DEBUG | 最详细的日志信息,典型应用场景是 问题诊断 |
INFO | 信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作 |
WARNING | 当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的 |
ERROR | 由于一个更严重的问题导致某些功能不能正常运行时记录的信息 |
CRITICAL | 当发生严重错误,导致应用程序不能继续运行时记录的信息 |
开发应用程序或部署开发环境时,可以使用DEBUG或INFO级别的日志获取尽可能详细的日志信息来进行开发或部署调试;
应用上线或部署生产环境时,应该使用WARNING或ERROR或CRITICAL级别的日志来降低机器的I/O压力和提高获取错误日志信息的效率。日志级别的指定通常都是在应用程序的配置文件中进行指定的。
说明:
- 上面列表中的日志等级是从上到下依次升高的,即:DEBUG < INFO < WARNING < ERROR < CRITICAL,而日志的信息量是依次减少的;
- 当为某个应用程序指定一个日志级别后,应用程序会记录所有日志级别大于或等于指定日志级别的日志信息,而不是仅仅记录指定级别的日志信息,
nginx
、ph
p等应用程序以及这里的python的logging模块都是这样的。同样,logging模块也可以指定日志记录器的日志级别,只有级别大于或等于该指定日志级别的日志记录才会被输出,小于该等级的日志记录将会被丢弃。
<1> 函数式使用
import logging
LOG_FORMAT = "%(asctime)s %(name)s %(levelname)s %(pathname)s %(message)s "#配置输出日志格式
DATE_FORMAT = '%Y-%m-%d %H:%M:%S %a ' #配置输出时间的格式,注意月份和天数不要搞乱了
logging.basicConfig(level=logging.DEBUG,
format=LOG_FORMAT,
datefmt = DATE_FORMAT ,
filename=r"d:\test\test.log" #有了filename参数就不会直接输出显示到控制台,而是直接写入文件
)
logging.debug("msg1")
logging.info("msg2")
logging.warning("msg3")
logging.error("msg4")
logging.critical("msg5")
logging.basicConfig()
函数包含参数说明
参数名称 | 描述 |
---|---|
filename | 指定日志输出目标文件的文件名(可以写文件名也可以写文件的完整的绝对路径,写文件名日志放执行文件目录下,写完整路径按照完整路径生成日志文件),指定该设置项后日志信心就不会被输出到控制台了 |
filemode | 指定日志文件的打开模式,默认为’a’。需要注意的是,该选项要在filename指定时才有效 |
format | 指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序。logging模块定义的格式字段下面会列出。 |
datefmt | 指定日期/时间格式。需要注意的是,该选项要在format中包含时间字段%(asctime)s时才有效 |
level | 指定日志器的日志级别 |
stream | 指定日志输出目标stream,如sys.stdout、sys.stderr以及网络stream。需要说明的是,stream和filename不能同时提供,否则会引发 ValueError 异常 |
style | Python 3.2中新添加的配置项。指定format格式字符串的风格,可取值为’%’、’{‘和’$’,默认为’%’ |
handlers | Python 3.3中新添加的配置项。该选项如果被指定,它应该是一个创建了多个Handler的可迭代对象,这些handler将会被添加到root logger。需要说明的是:filename、stream和handlers这三个配置项只能有一个存在,不能同时出现2个或3个,否则会引发ValueError异常。 |
logging模块中定义好的可以用于format格式字符串说明
字段/属性名称 | 使用格式 | 描述 |
---|---|---|
asctime | %(asctime)s | 将日志的时间构造成可读的形式,默认情况下是‘2016-02-08 12:00:00,123’精确到毫秒 |
name | %(name)s | 所使用的日志器名称,默认是’root’,因为默认使用的是 rootLogger |
filename | %(filename)s | 调用日志输出函数的模块的文件名; pathname的文件名部分,包含文件后缀 |
funcName | %(funcName)s | 由哪个function发出的log, 调用日志输出函数的函数名 |
levelname | %(levelname)s | 日志的最终等级(被filter修改后的) |
message | %(message)s | 日志信息, 日志记录的文本内容 |
lineno | %(lineno)d | 当前日志的行号, 调用日志输出函数的语句所在的代码行 |
levelno | %(levelno)s | 该日志记录的数字形式的日志级别(10, 20, 30, 40, 50) |
pathname | %(pathname)s | 完整路径 ,调用日志输出函数的模块的完整路径名,可能没有 |
process | %(process)s | 当前进程, 进程ID。可能没有 |
processName | %(processName)s | 进程名称,Python 3.1新增 |
thread | %(thread)s | 当前线程, 线程ID。可能没有 |
threadName | %(thread)s | 线程名称 |
module | %(module)s | 调用日志输出函数的模块名, filename的名称部分,不包含后缀即不包含文件后缀的文件名 |
created | %(created)f | 当前时间,用UNIX标准的表示时间的浮点数表示; 日志事件发生的时间–时间戳,就是当时调用time.time()函数返回的值 |
relativeCreated | %(relativeCreated)d | 输出日志信息时的,自Logger创建以 来的毫秒数; 日志事件发生的时间相对于logging模块加载时间的相对毫秒数 |
msecs | %(msecs)d | 日志事件发生事件的毫秒部分。logging.basicConfig()中用了参数datefmt,将会去掉asctime中产生的毫秒部分,可以用这个加上 |
说明
logging.basicConfig()
函数是一个一次性的简单配置工具使,也就是说只有在第一次调用该函数时会起作用,后续再次调用该函数时完全不会产生任何操作的,多次调用的设置并不是累加操作。如果要记录的日志中包含变量数据,可使用一个格式字符串作为这个事件的描述消息(logging.debug、logging.info等函数的第一个参数),然后将变量数据作为第二个参数*args的值进行传递,如:
logging.warning('%s is %d years old.', 'Tom', 10),
输出内容为
WARNING:root:Tom is 10 years old.
<2> 日志流处理流程:
日志流处理流程是一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)。
logging日志模块四大组件:
在介绍logging模块的日志流处理流程之前,我们先来介绍下logging模块的四大组件:
组件名称 | 对应类名 | 功能描述 |
---|---|---|
日志器 | Logger | 提供了应用程序可一直使用的接口 |
处理器 | Handler | 将logger创建的日志记录发送到合适的目的输出 |
过滤器 | Filter | 提供了更细粒度的控制工具来决定输出哪条日志记录,丢弃哪条日志记录 |
格式器 | Formatter | 决定日志记录的最终输出格式 |
logging模块就是通过这些组件来完成日志处理的,上面所使用的logging模块级别的函数也是通过这些组件对应的类来实现的。
这些组件之间的关系描述:
简单点说就是:日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。
(1) Handler类:
Handler对象的作用是(基于日志消息的level)将消息分发到handler指定的位置(文件、网络、邮件等)。Logger对象可以通过addHandler()方法为自己添加0个或者更多个handler对象。比如,一个应用程序可能想要实现以下几个日志需求:
Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略``Handler.setFormatter():给这个handler选择一个格式``Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个``filter``对象
需要说明的是,应用程序代码不应该直接实例化和使用Handler实例。因为Handler是一个基类,它只定义了素有handlers都应该有的接口,同时提供了一些子类可以直接使用或覆盖的默认行为。下面是一些常用的Handler:
Handler | 描述 |
---|---|
logging.StreamHandler | 将日志消息发送到输出到Stream,如std.out, std.err或任何file-like对象。 |
logging.FileHandler | 将日志消息发送到磁盘文件,默认情况下文件大小会无限增长 |
logging.handlers.RotatingFileHandler | 将日志消息发送到磁盘文件,并支持日志文件按大小切割 |
logging.hanlders.TimedRotatingFileHandler | 将日志消息发送到磁盘文件,并支持日志文件按时间切割 |
logging.handlers.HTTPHandler | 将日志消息以GET或POST的方式发送给一个HTTP服务器 |
logging.handlers.SMTPHandler | 将日志消息发送给一个指定的email地址 |
logging.NullHandler | 该Handler实例会忽略error messages,通常被想使用logging的library开发者使用来避免’No handlers could be found for logger XXX’信息的出现。 |
(2) Formater
类:
Formater
对象用于配置日志信息的最终顺序、结构和内容。与logging.Handler
基类不同的是,应用代码可以直接实例化Formatter类。另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个Formatter的子类来完成。
Formatter类的构造方法定义如下:
logging.Formatter.__init__(fmt``=``None``, datefmt``=``None``, style``=``'%'``)
可见,该构造方法接收3个可选参数:
一般直接用logging.Formatter(fmt, datefmt)
(3) Filter类(暂时了解)
Filter可以被Handler和Logger用来做比level更细粒度的、更复杂的过滤功能。Filter是一个过滤器基类,它只允许某个logger层级下的日志事件通过过滤。该类定义如下:
class logging.Filter(name='')
filter(record)
比如,一个filter实例化时传递的name参数值为’A.B’,那么该filter实例将只允许名称为类似如下规则的loggers产生的日志记录通过过滤:‘A.B’,‘A.B,C’,‘A.B.C.D’,‘A.B.D’,而名称为’A.BB’, 'B.A.B’的loggers产生的日志则会被过滤掉。如果name的值为空字符串,则允许所有的日志事件通过过滤。
filter方法用于具体控制传递的record记录是否能通过过滤,如果该方法返回值为0表示不能通过过滤,返回值为非0表示可以通过过滤。
说明:
- 如果有需要,也可以在filter(record)方法内部改变该record,比如添加、删除或修改一些属性
- 我们还可以通过filter做一些统计工作,比如可以计算下被一个特殊的logger或handler所处理的record数量等。
日志流处理简要流程:
1、创建一个logger
2、设置下logger的日志的等级
3、创建合适的Handler(FileHandler要有路径)
4、设置下每个Handler的日志等级
5、创建下日志的格式
6、向Handler中添加上面创建的格式
7、将上面创建的Handler添加到logger中
8、打印输出logger.debug\logger.info\logger.warning\logger.error\logger.critical
# 代码
import logging
def log():
#创建logger,如果参数为空则返回root logger
logger = logging.getLogger("nick")
logger.setLevel(logging.DEBUG) #设置logger日志等级
#这里进行判断,如果logger.handlers列表为空,则添加,否则,直接去写日志
if not logger.handlers:
#创建handler
fh = logging.FileHandler("test.log",encoding="utf-8")
ch = logging.StreamHandler()
#设置输出日志格式
formatter = logging.Formatter(
fmt="%(asctime)s %(name)s %(filename)s %(message)s",
datefmt="%Y/%m/%d %X"
)
#为handler指定输出格式
fh.setFormatter(formatter)
ch.setFormatter(formatter)
#为logger添加的日志处理器
logger.addHandler(fh)
logger.addHandler(ch)
return logger #直接返回logger
logger = log()
logger.warning("泰拳警告")
logger.info("提示")
logger.error("错误")
logger.debug("查错")
默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。
灵活配置日志级别,日志格式,输出位置:
import logging
file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',)
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
handlers=[file_handler,],
level=logging.ERROR
)
logging.error('你好')
日志切割
import time
import logging
from logging import handlers
sh = logging.StreamHandler()
rh = handlers.RotatingFileHandler('myapp.log', maxBytes=1024,backupCount=5)
fh = handlers.TimedRotatingFileHandler(filename='x2.log', when='s', interval=5, encoding='utf-8')
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
handlers=[fh,sh,rh],
level=logging.ERROR
)
for i in range(1,100000):
time.sleep(1)
logging.error('KeyboardInterrupt error %s'%str(i))
logger对象配置
import logging
logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log',encoding='utf-8')
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
logger.addHandler(ch)
logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')
logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。另外,可以通过:logger.setLevel(logging.Debug)设置级别,当然,也可以通过 fh.setLevel(logging.Debug)单对文件流设置某个级别。
re
模块就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
字符匹配(普通字符,元字符):
1 普通字符:大多数字符和字母都会和自身匹配
>>> re.findall('alvin','yuanaleSxalexwupeiqi')
2 元字符:. ^ $ * + ? { } [ ] | ( ) \
元字符
# . ^ $
# 重复原字符 * + ? { }
# [ ] | () \
re模块下的常用方法
import re
re.findall('a','alvin yuan') #返回所有满足匹配条件的结果,放在列表里
re.search('a','alvin yuan').group()
#函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以
# 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
re.match('a','abc').group() #同search,不过尽在字符串开始处进行匹配
ret=re.split('[ab]','abcd') #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(ret)#['', '', 'cd']
ret=re.sub('\d','abc','alvin5yuan6',1)
ret=re.subn('\d','abc','alvin5yuan6')
obj=re.compile('\d{3}')
ret=obj.search('abc123eeee')
print(ret.group())#123
import re
ret=re.finditer('\d','ds3sy4784a')
print(ret) #
print(next(ret).group())
print(next(ret).group())
json
模块我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
JSON表示的对象就是标准的JavaScript语言的对象一个子集,JSON和Python内置的数据类型对应如下:
import json
s = 'hi,yuan'
b = True
i = 10
l = [s,b,i]
d = {
"name":"yuan","age":23,"gender":"male"}
# 序列化
print(repr(json.dumps(s)))
print(repr(json.dumps(b)))
print(repr(json.dumps(i)))
print(repr(json.dumps(d)))
print(repr(json.dumps(d)))
# 结果
'"hi,yuan"'
'true'
'10'
'{"name": "yuan", "age": 23, "gender": "male"}'
'{"name": "yuan", "age": 23, "gender": "male"}'
该模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键=值)。
类似于以下配置文件:
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
python生成一个这样的文档,如下实现
import configparser
config = configparser.ConfigParser()
config["DEFAULT"] = {
'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '9',
'ForwardX11':'yes'
}
config['bitbucket.org'] = {
'User':'hg'}
config['topsecret.server.com'] = {
'Host Port':'50022','ForwardX11':'no'}
with open('example.ini', 'w') as configfile:
config.write(configfile)
查找文件
import configparser
config = configparser.ConfigParser()
#---------------------------查找文件内容,基于字典的形式
print(config.sections()) # []
config.read('example.ini')
print(config.sections()) # ['bitbucket.org', 'topsecret.server.com']
print('bytebong.com' in config) # False
print('bitbucket.org' in config) # True
print(config['bitbucket.org']["user"]) # hg
print(config['DEFAULT']['Compression']) #yes
print(config['topsecret.server.com']['ForwardX11']) #no
print(config['bitbucket.org']) #
for key in config['bitbucket.org']: # 注意,有default会默认default的键
print(key)
print(config.options('bitbucket.org')) # 同for循环,找到'bitbucket.org'下所有键
print(config.items('bitbucket.org')) #找到'bitbucket.org'下所有键值对
print(config.get('bitbucket.org','compression')) # yes get方法Section下的key对应的value
增删改除
import configparser
config = configparser.ConfigParser()
config.read('example.ini')
config.add_section('yuan')
config.remove_section('bitbucket.org')
config.remove_option('topsecret.server.com',"forwardx11")
config.set('topsecret.server.com','k1','11111')
config.set('yuan','k2','22222')
config.write(open('new2.ini', "w"))
import configparser
config = configparser.ConfigParser() # config 配置文件文件句柄
# config["DEFAULT"] = {'ServerAliveInterval': '45',
# 'Compression': 'yes',
# 'CompressionLevel': '10',
# 'ForwardX11':'yes'
# }
# config['bitbucket.org'] = {'User':'hg','alex':'sb'}
# config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}
# config['client'] = {'Host Port':'50022','ForwardX11':'no'}
# with open('example.ini', 'w') as configfile:
# config.write(configfile)
import configparser
# config = configparser.ConfigParser()
# print(config.sections()) # []
# config.read('example.ini')
# print(config.sections()) # ['bitbucket.org', 'topsecret.server.com']
# print('bytebong.com' in config) # False
# print('bitbucket.org' in config) # True
# print(config['bitbucket.org']["user"]) # hg
# print(config['DEFAULT']['Compression']) #yes
# print(config['topsecret.server.com']['ForwardX11']) #no
# print(config['bitbucket.org']) #
# for key in config['bitbucket.org']: # 注意,有default会默认default的键
# print(key)
# print(config.options('bitbucket.org')) # 同for循环,找到'bitbucket.org'下所有键
# print(config.items('bitbucket.org')) #找到'bitbucket.org'下所有键值对
# print(config.get('bitbucket.org','compression')) # yes get方法Section下的key对应的value