模块

时间相关命令

时间分为三种格式

1.时间戳:从1970年到现在的秒数

​ time.time

2.格式化的字符串形式

​ time.strftime(‘%Y-%m-%d %H:%M%S %p’)

3.结构化的时间

​ res=time.localtime

​ print(res)

​ print(res.tm_year)

4.datetime

​ import datetime

​ print(datetime.datetime.now())

​ 直接获取到格式化的时间格式

时间格式的转换

时间格式转换是其三种时间格式的相互转换,结构化时间(struct_time),时间戳(timestamp),格式化的字符串(format_string)

struct_time转换成时间戳

1
2
3
import time
s_time=time.localtime()
print(time.mktime(s_time))

时间戳转换成struct_time

1
2
tp_time=time.time()
print(time.localtime(tp_time))

strcut_time转换成格式化的字符串

1
2
s_time=time.localtime()
time.strftime('%Y-%m-%d %H:%M%S %p',s_time)

真正需要掌握的是format string <—> timestamp

random模块

1
2
3
4
5
6
7
8
9
10
import random

print(random.random()) #的到0到1之间的小数
random.randint(1,3) #大于等于1小于等于3的数
random.randrange(1,3) #大于等于1 小于3
~.choice(1,'aaa',[2,3]) #定义几个数随机取一个
~.sample(1,'23131d',[4,5]) #列表元素任意2个组合
~.uniform(1,3) #大于1小于3 的小树
item =[1,2,3,4,5]
random.shuffle(item)#打乱顺序

os模块

os模块是与操作系统交互的一个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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的大小
1
2
3
4
5
6
7
8
9
10
11
12
在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
>>> os.path.normcase('c:/windows\\system32\\')
'c:\\windows\\system32\\'


规范化路径,如..和/
>>> os.path.normpath('c://windows\\System32\\../Temp/')
'c:\\windows\\Temp'

>>> a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
>>> print(os.path.normpath(a))
/Users/jieli/test1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
os路径处理
#方式一:推荐使用
import os
#具体应用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
os.path.abspath(__file__),
os.pardir, #上一级
os.pardir,
os.pardir
))
sys.path.insert(0,possible_topdir)


#方式二:不推荐使用
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

sys模块

1
2
import sys
print(sys.argv)

sys.argv用于获取向文件传递的参数

例如:

python3 run.py 1 2 3

其中的1, 2,3就分别是三个参数

sys.argv[0]为文件名, 123,分别就是后面对应的位置参数。

例如:

以argv来实现cp命令(cp 源文件 目标文件),实现复制粘贴文件的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
import sys
cs_1=sys.argv[1]
cs_2=sys.argv[2]

try:
with open(r'%s' %cs_1,mode="rb") as file1:
a=file1.read()
with open(r'%s' %cs_2,mode="wb+") as file2:
b=file2.write(a)
except IOError:
print("没有该文件")
else:
print("内容写入文件成功")

执行效果:(得在Windows命令行console执行)

(pyproject) E:\pyproject\py_study1>python study1.py upload_file.py 2.py
内容写入文件成功

image-20210924160248941

打印进度条:

1
2
3
4
5
6
7
import time
res = ''
for i in range(50):
res+='#'
time.sleep(0.5)
print('\r[%-50s]' % res,end='')
#%s 为百分号替代符号,中间的-50,-为左对齐,50为其长度固定为50,由于只输出一行,让其为每次叠加一个#的进度条,所以其换行符为空,并且\r跳到其行首,使其覆盖

模拟打印下载进度条:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import time
recv_size=0

total_size=30000

while recv_size < total_size:
time.sleep(0.1)
recv_size+=1024

percent= recv_size / total_size
if percent > 1:
percent = 1
res= int(50 * percent) * '#'
print('\r[%-50s] %d%%') % (res,int(100*percent)),end='')
#recv_size和total_size模拟其文件大小以及已下载的数据大小
#sleep模拟下载速度,使其不会太快加载完。
#recv_size/total_size得到的分数为其下载进度,\r[%-50s]为其打印进度条,%d%%显示百分比,百分比为其下载进度分数x100.但recv_size一直累加可能会超出总大小本身,其比例也会超过100%,这是可以用if 判断其大于1时使其等于1.

shutil模块

引入: import shutil

copy()
功能:复制文件
格式:shutil.copy(‘来源文件’,’目标地址’)
返回值:复制之后的路径

copy2()
功能:复制文件,保留元数据
格式:shutil.copy2(‘来源文件’,’目标地址’)
返回值:复制之后的路径

copyfileobj()
将一个文件的内容拷贝的另外一个文件当中
格式:shutil.copyfileobj(open(来源文件,’r’),open(’目标文件’,’w’))
返回值:无

copyfile()
功能:将一个文件的内容拷贝的另外一个文件当中
格式:shutil.copyfile(来源文件,目标文件)
返回值:目标文件的路径

copytree()
功能:复制整个文件目录
格式:shutil.copytree(来源目录,目标目录)
返回值:目标目录的路径
注意:无论文件夹是否为空,均可以复制,而且会复制文件夹中的所有内容

copymode()
功能:拷贝权限

copystat()
功能:拷贝元数据(状态)

rmtree()
功能:移除整个目录,无论是否空
格式:shutil.rmtree(目录路径)
返回值:无

move()
功能:移动文件或者文件夹
格式:shutil.move(来源地址,目标地址)
返回值:目标地址

which()
功能:检测命令对应的文件路径
格式:shutil.which(‘命令字符串’)
返回值:命令文件所在位置
注意:window和linux不太一样。 window的命令都是.exe结尾,linux则不是

disk_usage()
功能:检测磁盘使用信息
格式:disk_usage(‘盘符’)
返回值:元组

归档和解包操作
归档:将多个文件合并到一个文件当中,这种操作方式就是归档。

解包:将归档的文件进行释放。

压缩:压缩时将多个文件进行有损或者无损的合并到一个文件当中。

解压缩:就是压缩的反向操作,将压缩文件中的多个文件,释放出来。

注意:压缩属于归档!
make_archive()
功能:归档函数,归档操作
格式:shutil.make_archive(‘目标文件路径’,’归档文件后缀’,’需要归档的目录’)
返回值:归档文件的最终路径

unpack_archive()
功能:解包操作
格式:shutil.unpack_archive(‘归档文件路径’,’解包目标文件夹’)
返回值:None
注意:文件夹不存在会新建文件夹

get_archive_formats()
功能:获取当前系统已注册的归档文件格式(后缀)
格式:shutil.get_archive_formats()

get_unpack_formats()
功能:获取当前系统已经注册的解包文件格式(后缀)
格式:shutil.get_unpack_formats()
返回值:列表 [(后缀,解释),(后缀,解释),(后缀,解释)…]

json&pickle模块

之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。

1
2
3
4
1 import json
2 x="[null,true,false,1]"
3 print(eval(x)) #报错,无法解析null类型,而json就可以
4 print(json.loads(x))

什么是序列化?

我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。

为什么要序列化?

1:持久保存状态

需知一个软件/程序的执行就在处理一系列状态的变化,在编程语言中,’状态’会以各种各样有结构的数据类型(也可简单的理解为变量)的形式被保存在内存中。

内存是无法永久保存数据的,当程序运行了一段时间,我们断电或者重启程序,内存中关于这个程序的之前一段时间的数据(有结构)都被清空了。

在断电或重启程序之前将程序当前内存中所有的数据都保存下来(保存到文件中),以便于下次程序执行能够从文件中载入之前的数据,然后继续执行,这就是序列化。

具体的来说,你玩使命召唤闯到了第13关,你保存游戏状态,关机走人,下次再玩,还能从上次的位置开始继续闯关。或如,虚拟机状态的挂起等。

2:跨平台数据交互

序列化之后,不仅可以把序列化后的内容写入磁盘,还可以通过网络传输到别的机器上,如果收发的双方约定好实用一种序列化的格式,那么便打破了平台/语言差异化带来的限制,实现了跨平台数据交互。

反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。

json

如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:

image-20210927145134605

如何序列化与反序列化

1
2
3
4
5
import json
res=json.dumps([1,'aaa',True,False])
print(res.type(res))
l=json.loads(res)
print(l,type(l))

运行结果:

[1, “aaa”, true, false] <class ‘str’>
[1, ‘aaa’, True, False] <class ‘list’>

json.dumps是序列化转换,将列表转换为json格式,其格式变为了str。

json.loads是反序列化转换,将其又转回了原来的列表格式。

示例2:存储为json格式

1
2
3
4
import json
res=json.dumps([1,'aaa',True,False])
with open("1.json",mode="wt",encoding='utf-8') as file:
file.write(res)

运行结果:

image-20210927151042187

再读取json格式将其反序列化转换成原格式:

1
2
3
4
5
import json
with open("1.json",mode='rt') as file:
a=file.read()
b=json.loads(a)
print(b)

运行结果:

[1, ‘aaa’, True, False]

简单方法实现:

1
2
3
4
import json
with open("1.json",mode="wt",encoding='utf-8') as file:
json.dump([1, 'aaa', True, False],file)

1
2
3
4
import json
with open("1.json",mode='rt') as file:
l=json.load(file)
print(l)

dump和load可以省略其文件的write和read方法

pickle

1
2
3
import pickle
res=pickle.dumps({1,2,3,4,5})
print(res,type(res))

将python序列化转换成pickle形式,反序列化为loads,与json一致。

configparser模块

配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
# 注释1
; 注释2

[section1]
k1 = v1
k2:v2
user=egon
age=18
is_admin=true
salary=31
[section2]
k1 = v1

读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import configparser

config=configparser.ConfigParser()
config.read('a.cfg')

#查看所有的标题
res=config.sections() #['section1', 'section2']
print(res)

#查看标题section1下所有key=value的key
options=config.options('section1')
print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary']

#查看标题section1下所有key=value的(key,value)格式
item_list=config.items('section1')
print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')]

#查看标题section1下user的值=>字符串格式
val=config.get('section1','user')
print(val) #egon

#查看标题section1下age的值=>整数格式
val1=config.getint('section1','age')
print(val1) #18

#查看标题section1下is_admin的值=>布尔值格式
val2=config.getboolean('section1','is_admin')
print(val2) #True

#查看标题section1下salary的值=>浮点型格式
val3=config.getfloat('section1','salary')
print(val3) #31.0

改写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import configparser

config=configparser.ConfigParser()
config.read('a.cfg',encoding='utf-8')


#删除整个标题section2
config.remove_section('section2')

#删除标题section1下的某个k1和k2
config.remove_option('section1','k1')
config.remove_option('section1','k2')

#判断是否存在某个标题
print(config.has_section('section1'))

#判断标题section1下是否有user
print(config.has_option('section1',''))


#添加一个标题
config.add_section('egon')

#在标题egon下添加name=egon,age=18的配置
config.set('egon','name','egon')
config.set('egon','age',18) #报错,必须是字符串


#最后将修改的内容写入文件,完成最终的修改
config.write(open('a.cfg','w'))

基于上述方法添加一个ini文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import configparser

config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '9'}

config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022' # mutates the parser
topsecret['ForwardX11'] = 'no' # same here
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini', 'w') as configfile:
config.write(configfile)

hashlib模块

1
2
3
4
5
# 1、什么叫hash:hash是一种算法(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),该算法接受传入的内容,经过运算得到一串hash
# 2、hash值的特点是:
#2.1 只要传入的内容一样,得到的hash值必然一样=====>要用明文传输密码文件完整性校验
#2.2 不能由hash值返解成内容=======》把密码做成hash值,不应该在网络传输明文密码
#2.3 只要使用的hash算法不变,无论校验的内容有多大,得到的hash值长度是固定的

hash算法就像一座工厂,工厂接收你送来的原材料(可以用m.update()为工厂运送原材料),经过加工返回的产品就是hash值

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 1 import hashlib
2
3 m=hashlib.md5()# m=hashlib.sha256()
4
5 m.update('hello'.encode('utf8'))
6 print(m.hexdigest()) #5d41402abc4b2a76b9719d911017c592
7
8 m.update('alvin'.encode('utf8'))
9
10 print(m.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af
11
12 m2=hashlib.md5()
13 m2.update('helloalvin'.encode('utf8'))
14 print(m2.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af
15
16 '''
17 注意:把一段很长的数据update多次,与一次update这段长数据,得到的结果一样
18 但是update多次为校验大文件提供了可能。
19 '''

以上加密算法虽然依然非常厉害,但时候存在缺陷,即:通过撞库可以反解。所以,有必要对加密算法中添加自定义key再来做加密。

1
2
3
4
5
6
7
1 import hashlib
2
3 # ######## 256 ########
4
5 hash = hashlib.sha256('898oaFs09f'.encode('utf8'))
6 hash.update('alvin'.encode('utf8'))
7 print (hash.hexdigest())#e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7

python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密:

1
2
3
4
5
import hmac
h1=hmac.new('hello'.encode('utf-8'),digestmod='md5')
h1.update('world'.encode('utf-8'))

print(h1.hexdigest())

suprocess模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 1 import  subprocess
2
3 '''
4 sh-3.2# ls /Users/egon/Desktop |grep txt$
5 mysql.txt
6 tt.txt
7 事物.txt
8 '''
9
10 res1=subprocess.Popen('ls /Users/jieli/Desktop',shell=True,stdout=subprocess.PIPE)
11 res=subprocess.Popen('grep txt$',shell=True,stdin=res1.stdout,
12 stdout=subprocess.PIPE)
13
14 print(res.stdout.read().decode('utf-8'))
15
16
17 #等同于上面,但是上面的优势在于,一个数据流可以和另外一个数据流交互,可以通过爬虫得到结果然后交给grep
18 res1=subprocess.Popen('ls /Users/jieli/Desktop |grep txt$',shell=True,stdout=subprocess.PIPE)
19 print(res1.stdout.read().decode('utf-8'))
20
21
22 #windows下:
23 # dir | findstr 'test*'
24 # dir | findstr 'txt$'
25 import subprocess
26 res1=subprocess.Popen(r'dir C:\Users\Administrator\PycharmProjects\test\函数备课',shell=True,stdout=subprocess.PIPE)
27 res=subprocess.Popen('findstr test*',shell=True,stdin=res1.stdout,
28 stdout=subprocess.PIPE)
29
30 print(res.stdout.read().decode('gbk')) #subprocess使用当前系统默认编码,得到结果为bytes类型,在windows下需要用gbk解码

logging模块

1.日志级别以及模块

1
2
3
4
5
6
import logging
logging.debug("调试")
logging.info("消息信息")
logging.warning("警告信息")
logging.error("错误error信息")
logging.critical("严重信息")

logging为模块名,有5种输出级别,对应调试,信息,警告,错误,严重错误。

该段代码运行效果:

image-20211008145648843

logging.告警级别 本质上就是直接在对应位置输出对应信息,信息内容包含在括号里面,这里打印时默认只输出了warning及其以上的信息,说明默认输出日志级别为warning。

logging.basicConfig

#======介绍
可在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有
filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到 sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。

format参数中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s用户输出的消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19




#========使用
import logging
logging.basicConfig(filename='access.log',
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level=10)

logging.debug('调试debug')
logging.info('消息info')
logging.warning('警告warn')
logging.error('错误error')
logging.critical('严重critical')


part2: 可以为logging模块指定模块级的配置,即所有logger的配置

filename指定了日志文件,format指定其日志输出格式,datefmt指定日志输出时间的格式,level指定其日志输出级别,默认为30

level为10,20,30,40,50,对应调试,信息,警告,错误和严重错误。

日志输出结果:

image-20211008151019274

如果这里不指定filename则默认输出到pycharm屏幕(python屏幕)

image-20211008151301307

日志字典

其作用为让日志在读取格式时直接通过自身模块从字典里读取形成多种格式的方法,字典本身多个key固定的名称。

settings.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
standard_format = '%(asctime)s - %(threadName)s:%(thread)d - 日志名字:%(name)s - %(filename)s:%(lineno)d -' \
'%(levelname)s - %(message)s'

simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'

test_format = '%(asctime)s] %(message)s'

# 3、日志配置字典
LOGGING_DIC = {
'version': 1, #版本,可以随意定义
'disable_existing_loggers': False, # 禁用已经存在的logger实例,固定格式
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
'test': {
'format': test_format
},
}, # 定义日志 格式化的 工具,上面定义的standard_format,simple_format,test_format对应三种输出格式
'filters': {},# 过滤
# handlers是日志的接收者,不同的handler会将日志输出到不同的位置
'handlers': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
# 'maxBytes': 1024*1024*5, # 日志大小 5M
'maxBytes': 1000,
'backupCount': 5,
'filename': 'a1.log', # os.path.join(os.path.dirname(os.path.dirname(__file__)),'log','a2.log')
'encoding': 'utf-8',
'formatter': 'standard',

},
#打印到文件的日志,收集info及以上的日志
'other': {
'level': 'DEBUG',
'class': 'logging.FileHandler', # 保存到文件
'filename': 'a2.log', # os.path.join(os.path.dirname(os.path.dirname(__file__)),'log','a2.log')
'encoding': 'utf-8',
'formatter': 'test',

},
},
# loggers是日志的产生者,产生的日志会传递给handler然后控制输出
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'kkk': {
'handlers': ['console','other'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
},
'终端提示': {
'handlers': ['console',], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
},
'': {
'handlers': ['default', ], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
},
},
}

src.py(主文件):

1
2
3
4
5
6
7
8
import logging #导入logging模块

import settings #导入settings文件,上面定义的settings.py
from logging import config,getLogger #导入config和getlogger 这里需要单独导入

config.dictConfig(settings.LOGGING_DIC) #LOGGING_DIC为字典名,这里settings导入字典名,然后dictconfig解析。固定格式,只需将LOGGING_DIC替换为需要的字典名即可
logger4=getLogger('终端提示') #loggers为发送者,这里也是将日志输出者定义为对应的loggers,并将其定义成一个变量。
logger4.info('logger4产生的info日志')#调用info发送日志。

代码步骤:

settings.py:

standard_format,simple_format,test_format定义三种输出格式

LOGGING_DIC:

​ 字典定义了日志输出相关配置

1.version,disable_existing_loggers 其格式固定就行

2.formatters 其中key也是固定的,里面定义了三种日志输出格式,这里里面的key和value都是自己定义的,其三种value也对应一开始定义的三种变量。

3.filters 略(过滤)

4.handlers:

1
handlers是日志的接收者,不同的handler会将日志输出到不同的位置

这里定义了两种输出位置。level为输出级别,class为输出方式,formatter为其对应输出格式,filename输出文件,encoding输出字符。这里相当于定义其日志输出位置以及将上面定义的日志输出格式赋给日志这个日志输出位置。

5.loggers:

1
# loggers是日志的产生者,产生的日志会传递给handler然后控制输出

这里loggers与handlers相当于是下级对上级,loggers产生日志,handlers接受日志,两边都可以设置其level,如果loggers的level低于handlers,那么实际日志输出只会根据handlers的level来进行输出(因为loggers发送了低于handlers的日志,但handlers只会接受并输出自己的level以上的。),正常情况两边level应一致。

handlers定义其输出位置(方式),level为其输出级别,propagate固定false。

如果定义的loggers为空 ‘’ 的话,后面在使用getlogger找不到loggers的所有日志名都会匹配到空。

src.py

如上备注所示。

其本身格式基本上为固定,直接拿着两个文件稍作修改就可以用于各种工作场景,无需过分理解,能看懂代码格式即可

日志字典本身就算是python日志的功能之一,所以其字典里面需要定义固定的key让其logging模块去解析它。而非自己定义一个字典再自己去解析,其格式固定。

字典顺序:

loggers(日志输出者)-》handlers(接受者)-》formatters(日志输出格式(standard_format,simple_format,test_format)

日志轮转:

相当于日志备份,logging自带日志备份,可以设置日志最大大小和备份日志最大个数

image-20211009154143282

在字典handlers中有两个设置:maxbytes和backupcount

maxbytes为最大大小,其格式为字节

backupcount是最大备份文件为多少

1
2
3
4
5
6
import settings #导入settings文件,上面定义的settings.py
from logging import config,getLogger #导入config和getlogger 这里需要单独导入

config.dictConfig(settings.LOGGING_DIC) #LOGGING_DIC为字典名,这里settings导入字典名,然后dictconfig解析。固定格式,只需将LOGGING_DIC替换为需要的字典名即可
logger4=getLogger('随便输入') #loggers为发送者,这里也是将日志输出者定义为对应的loggers,并将其定义成一个变量。
logger4.info('logger4产生的info日志')#调用info发送日志。

运行主代码程序输出日志以后,当日志大小大于5字节,就会备份成”文件名.1”,然后如果再执行程序,则会将1备份成2,将源文件备份成1,依次类推到5。

image-20211009154312364


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!