内置模块
序列化模块(常用)
- 本质就是将一种数据结构(如字典、列表)等转换成一个特殊的序列(特殊的字符串或者bytes)并且还可以反转回去的过程就叫做序列化
- 主要用途:文件读写数据,网络传输数据
json 模块 ( 通用 ) / str类型
定义
- 是所有语言公认的一种序列
- json序列化只支持部分Python数据结构:dict,list, tuple,str,int, float,True,False,None
- 存取文件时 文件为 "文件名.json"
序列化模块中使用最多的的就是json模块
dumps、loads → 网络传输 / 文件存取 (单 / 多数据)
import json
#序列化:json.dumps()
dic = {'k1':'v1','k2':'v2','k3':'v3'} # 也可以处理嵌套的数据类型
str_dic = json.dumps(dic) #序列化:将一个字典转换成一个字符串
print(type(str_dic),str_dic) #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"}
#注意,json转换完的字符串类型的字典中的字符串是由""表示的
#反序列化: json.loads()
dic2 = json.loads(str_dic) #反序列化:将一个字符串格式的字典转换成一个字典
#注意,要用json的loads功能处理的字符串类型的字典中的字符串必须由""表示
print(type(dic2),dic2) #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
dump、load → 单个数据结构文件存取
import json
# json.sump(数据变量,文件句柄) 写入文件
with open('json_file.json', 'w') as f:
dic = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
json.dump(dic, f) # dump方法接收一个文件句柄,直接将字典转换成json字符串 写入文件
# json文件也是文件,就是专门存储json字符串的文件。
# json.load(文件句柄) 读出文件
with open('json_file.json') as f:
dic2 = json.load(f) # load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
print(type(dic2), dic2) # <class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
json序列化存储单 / 多个数据到同一个文件中
import json
# 单个数据 存在 同一个文件中
import json
dic = {'username': '太白', 'password': 123,'status': False}
s_dict = json.dumps(dic)
with open('jsonlx.json',encoding='utf-8',mode='r+') as f1:
f1.write(s_dict)
f1.seek(0,0)
content = f1.read()
print(json.loads(content))
# {'username': '太白', 'password': 123, 'status': False}
print(type(json.loads(content))) # <class "dict">
# 多个数据 存在 同一个文件中
dic1 = {'name': 'oldboy1'}
dic2 = {'name': 'oldboy2'}
dic3 = {'name': 'oldboy3'}
with open('序列化.json', encoding='utf-8', mode="w") as f:
str1, str2, str3 = json.dumps(dic1), json.dumps(dic2), json.dumps(dic3)
f.write(f"{str1}
{str2}
{str3}
") # 格式化
# 读取多行文件内容
with open('序列化', encoding='utf-8') as f:
for line in f:
print(json.loads(line))
其他参数说明
ensure_ascii (确认是ASC码?)
- ensure_ascii = True 非ASCII显示为 uXXXX序列
- ensure_ascii = False 可正常显示
- 配合 dump / dumps 使用
# ensure_ascii = False / True 默认是True
import json
dic = {'username': '太白', 'password': 123, 'status': False}
ret = json.dumps(dic, ensure_ascii=False)
print(ret) # {"username": "太白", "password": 123, "status": false}
ret = json.dumps(dic, ensure_ascii=True) 或者 ret = json.dumps(dic)
print(ret) # {"username": "u592au767d", "password": 123, "status": false}
separators 分隔符
- 第一个分隔符是隔开每个键值对 ,第二个是分隔开每个key和value 默认的就是 原字典 格式分隔符 ( " , : " )
- 可自定义分隔符
# separators = "_?"
import json
dic = {'username': '太白', 'password': 123, 'status': False}
ret = json.dumps(dic) # 默认是字典本身的默认分隔符
print(ret) # {"username": "u592au767d", "password": 123, "status": false}
ret = json.dumps(dic,separators = "_?")
print(ret) # {"username"?"u592au767d"_"password"?123_"status"?false}
sort_keys 排序
- sort_keys = True 将数据 根据keys的值进行排序
- sort_keys = False 不排序
# sort_keys 默认是False
import json
dic = {'username': '太白', 'password': 123, 'status': False}
print(json.dumps(dic)
#{"username": "u592au767d", "password": 123, "status": false}
print(json.dumps(dic,sort_keys = True)) # 用key的首字母去排序
#{"password": 123, "status": false, "username": "u592au767d"}
pickle 模块 (限python) / bytes类型
定义
将Python所有的数据结构以及对象等转化成bytes类型,然后还可以反序列化还原回去。
- 只能是Python语言遵循的一种数据转化格式,只能在python语言中使用
- 支持Python所有的数据类型包括实例化对象
- dumps 与 dump 转化成的都是bytes类型数据
- 存取文件时 文件为 "文件名.pickle"
- dump / dumps 都是转成bytes类型数据
dumps、loads → 只用于网络传输
- 本地(数据类型) dumps → 网络(bytes类型) loads → 接收方(数据类型)
import pickle
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = pickle.dumps(dic)
print(str_dic) # bytes类型
dic2 = pickle.loads(str_dic)
print(dic2) # 字典
dump、load → 单 / 多个数据 文件存取
# 多个数据写入文件
l1 = ['wusir', '太白', '小黑1', 666]
l2 = ['wusir', '太白', '小黑2', 666]
l3 = ['wusir', '太白', '小黑3', 666]
with open('pickle_1.pickle', mode='wb') as f1:
pickle.dump(l1, f1)
pickle.dump(l2, f1)
pickle.dump(l3, f1)
# 多个数据读取
with open('pickle_1.pickle', mode='rb') as f1:
ret1 = pickle.load(f1)
ret2 = pickle.load(f1)
ret3 = pickle.load(f1)
print(ret1, ret2, ret3)
shevle模块 (3.4版新出)
- 只能在文件存取方面使用
os模块
# 当前执行这个python文件的工作目录相关的工作路径
# 目录指的是:文件夹 当前目录,工作目录,父级目录:指的都是一个,就是本文件所在的文件夹
import os
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 **
print(os.getcwd()) # D:Python work
os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd **
os.curdir 返回当前目录: ('.') **
print(os.curdir) # .
os.pardir 获取当前目录的父目录字符串名:('..') **
print(os.pardir) # ..
# 和文件夹相关
# (相对路径 直接写入文件名 , 绝对路径 (r"D:adsxx") r 为转译 分隔符 )
# 创建 / 删除 多级目录
os.makedirs('dirname1/dirname2') (创建多级目录)多层递归目录 ***
os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 *** 删除(截止)到有文件的文件夹之前
# 创建 / 删除 单级目录
os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname ***
os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname ***
os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 **
print(os.listdir(path))
# 和文件相关
os.remove() 删除一个文件 ***
os.rename("oldname","newname") 重命名文件/目录 ***
os.stat('path/filename') 获取文件/目录信息 **
print(os.stat(path)) # 返回文件的信息 / 大小 / 访问时间 / 修改时间 et
# 和操作系统差异相关
# os.sep 输出操作系统特定的路径分隔符,win下为"\",Linux下为"/" *
# os.linesep 输出当前平台使用的行终止符,win下为"
",Linux下为"
" *
# os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为: *
# os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix' *
# 和执行系统命令相关
# os.system("bash command") 运行shell命令,直接显示 **
# os.popen("bash command).read() 运行shell命令,获取执行结果 **
os.environ 获取系统环境变量 **
#path系列,和路径相关
os.path.abspath(path) 返回path规范化的绝对路径 ***
print(os.path.abspath(path)) # 返回绝对路径
print(__file__) *** 动态获取当前文件的绝对路径 ***
os.path.split(path) 将path分割成目录和文件名的元组返回 ***
print(os.path.split(path)) # 返回一个两个元素的元组 (a,b) a为工作路径 b 为文件名
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 ** / 获取父级目录
print(os.path.dirname(os.path.dirname(__file__))) # 获取当前文件的爷爷级路径
os.path.basename(path) 返回path最后的文件名。如何path以/或结尾,那么就会返回空值,即os.path.split(path)的第二个元素。 ** / 获取 文件名
print(os.path.basename(path)) # 获取 文件名
os.path.exists(path) # 如果path存在,返回True;如果path不存在,返回False ***
/ 判断path是否存在
print(os.path.exists(path)) # 判断路径是否存在
os.path.isabs(path) # 如果path是绝对路径,返回True ** / 是不是绝对路径
print(os.path.isabs(path)) # 判断是否绝对路径
os.path.isfile(path) # 如果path是一个存在的文件,返回True。否则返回False ***
print(os.path.isfile(path)) # 判断是否文件路径 路径中必须带文件才返回True
os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False ***
/ 判断是不是一个目录 (文件夹)
os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 *** (不要加分隔符) / 创建目录
print(os.path.join("D","Python work","day练习.py")) # DPython workday练习.py
os.path.getatime(path) 返回path所指向的文件或者目录的最后访问时间 **
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间 **
os.path.getsize(path) 返回path的大小 ***
print(os.path.getsize(r"D:Python workday练习.py")) # 文件大小
sys ( 系统 )模块
sys.path 返回模块的搜索路径
sys.argv # 命令行参数List,第一个元素是程序本身路径
sys.exit(n) # 退出程序,正常退出时exit(0),错误退出sys.exit(1)
sys.version # 获取Python解释程序的版本信息
sys.path # 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 ***
sys.platform # 返回操作系统平台名称
hashlib模块
- 摘要算法 / 加密算法 / 哈希算法 / 散列算法 等等
特征以及使用要点
- bytes类型数据 → 通过hashlib算法 → 固定长度的字符串
- 不同的bytes类型数据转化成的结果一定不同
- 相同的bytes类型数据转化成的结果一定相同
- 此转化过程不可逆
用途
- 密码的加密
- 文件一致性校验
hashlib模块就相当于一个算法的集合,这里面包含着很多的算法,算法越高,转化成的结果越复杂,安全程度越高,相应的效率就会越低。
密码的加密
# md5 系列
# 密码加密
import hashlib
ret = hashlib.md5()
ret.update('123'.encode('utf-8'))
s = ret.hexdigest()
print(s,type(s))
# 202cb962ac59075b964b07152d234b70 <class 'str'> 加密后的"123"
# 加固定盐
ret = hashlib.md5('xxx教育'.encode('utf-8')) # 加固定的"盐"
ret.update('123456'.encode('utf-8'))
s = ret.hexdigest()
print(s,type(s))
# 加动态的盐
username = input('输入用户名:').strip()
password = input('输入密码').strip()
ret = hashlib.md5(username[::2].encode('utf-8')) # 加动态"盐"
ret.update(password.encode('utf-8'))
s = ret.hexdigest()
print(s)
# sha系列: 安全系数高,耗时高.
# 加盐,加动态盐
ret = hashlib.sha512()
ret.update('123456fdklsajflsdfjsdlkafjafkl'.encode('utf-8'))
s = ret.hexdigest()
print(s,type(s))
文件一致性校验
import hashlib
s1 = '男孩 最好的python 是 白'
# 1
ret = hashlib.md5()
ret.update(s1.encode('utf-8'))
print(ret.hexdigest()) # 90c56d265a363292ec70c7074798c913
# 分步update
ret = hashlib.md5()
ret.update('男孩'.encode('utf-8'))
ret.update(' 最好的python'.encode('utf-8'))
ret.update(' 是'.encode('utf-8'))
ret.update(' 白'.encode('utf-8'))
print(ret.hexdigest()) # 90c56d265a363292ec70c7074798c913
大文件校验
import hashlib
def md5_file(path):
ret = hashlib.md5()
with open(path,mode='rb') as f1:
while 1:
content = f1.read(1024) # 分开校验 效率快
if content:
ret.update(content)
else:
return ret.hexdigest()
print(md5_file(r'D:s23day17python-3.7.4rc1-embed-win32.zip'))
time模块
在Python中,通常有这三种方式来表示时间:时间戳、元组(struct_time)、格式化的时间字符串:
- 时间戳
- 格式化时间
- 结构化时间
时间戳 (timestamp) / 计算机能够识别的时间
- 时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
- time.time()
import tmie
print(time.time()) # 时间戳 1502332424.34242 获取当前时间戳 (type → )
time.sleep(5) # 延迟5秒 推迟指定的时间运行。单位为秒。
格式化时间 / 人能够看懂的时间
- 格式化的时间字符串(Format String): ‘1999-12-06’
- time.strftime()
import time
print(time.strftime("%Y-%m-%d %H:%M:%S)) # 2019-6-1 12:21:22 字符串类型
print(time.strftime("%y-%m-%d %X")) # 19-06-28 16:00:19
print(time.strftime("%Y-%m-%d %H-%M-%S")) # 2019-06-28 16-01-20 (注意y的大小写)
格式化时间 参考代码
%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59)
%S 秒(00-59)
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期天为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%Z 当前时区的名称
%% %号本身
元组(struct_time) 结构化时间 / 用来操作时间的
- struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天等)
- time.localtime()
import time
time.localtime()
# 打印结果 : time.struct_time(tm_year=2019, tm_mon=6, tm_mday=28, tm_hour=16, tm_min=4, tm_sec=40, tm_wday=4, tm_yday=179, tm_isdst=0) / 元组类型
索引 Andex | 属性 Attribute | 值 Values |
---|---|---|
0 | tm_year (年) | 例: 2011 |
1 | tm_mom (月) | 1-12 |
2 | tm_mday (日) | 1-31 |
3 | tm_hour (时) | 0-23 |
4 | tm_min (分) | 0-59 |
5 | tm_sec (秒) | 0-60 |
6 | tm_wday (weekday) | 0-6 / 0表示周一 |
7 | tm_yday (一年中的第几天) | 1-366 |
8 | tm_isdst (是否是夏令时) | 默认为 0 |
几种格式之间的转换
格式化时间 ----> 结构化时间
# 格式化时间 ----> 结构化时间
# ft = time.strftime('%Y/%m/%d %H:%M:%S') ----> st = time.strptime(ft,'%Y/%m/%d %H:%M:%S')
import time
ft = time.strftime('%Y/%m/%d %H:%M:%S') # 格式化时间
print(ft)# 2019/06/28 16:08:45
st = time.strptime(ft,'%Y/%m/%d %H:%M:%S') # 元组 / 结构化时间
print(st)
# time.struct_time(tm_year=2019, tm_mon=6, tm_mday=28, tm_hour=16, tm_min=8, tm_sec=45, tm_wday=4, tm_yday=179, tm_isdst=-1)
结构化时间 ---> 时间戳
# 结构化时间 ---> 时间戳
# st = time.localtime() ---> t = time.mktime(st)
import time
st = time.localtime()
t = time.mktime(st)
print(t) # 1561709641.0
时间戳 ----> 结构化时间
# 时间戳 ----> 结构化时间
import time
t = time.time()
st = time.localtime(t)
print(st)
结构化时间 ---> 格式化时间
# 结构化时间 ---> 格式化时间
import time
st = time.localtime()
ft = time.strftime('%Y/%m/%d %H:%M:%S',st)
print(ft)
格式 / 数据转换
#结构化时间 --> %a %b %d %H:%M:%S %Y串
#time.asctime(结构化时间) 如果不传参数,直接返回当前时间的格式化串
>>>time.asctime(time.localtime(1500000000))
'Fri Jul 14 10:40:00 2017'
>>>time.asctime()
'Mon Jul 24 15:18:33 2017'
#时间戳 --> %a %d %d %H:%M:%S %Y串
#time.ctime(时间戳) 如果不传参数,直接返回当前时间的格式化串
>>>time.ctime()
'Mon Jul 24 15:19:07 2017'
>>>time.ctime(1500000000)
'Fri Jul 14 10:40:00 2017'
t = time.time()
ft = time.ctime(t)
print(ft)
st = time.localtime()
ft = time.asctime(st)
print(ft)
计算时间差
import time
true_time=time.mktime(time.strptime('2017-09-11 08:30:00','%Y-%m-%d %H:%M:%S'))
time_now=time.mktime(time.strptime('2017-09-12 11:00:00','%Y-%m-%d %H:%M:%S'))
dif_time=time_now-true_time
struct_time=time.gmtime(dif_time)
print('过去了%d年%d月%d天%d小时%d分钟%d秒'%(struct_time.tm_year-1970,struct_time.tm_mon-1,
struct_time.tm_mday-1,struct_time.tm_hour,
struct_time.tm_min,struct_time.tm_sec))
datetime模块
- 设置 / 调整 / 修改 时间数据
# datatime模块
import datetime
now_time = datetime.datetime.now() # 现在的时间
# 只能调整的字段:weeks days hours minutes seconds
print(datetime.datetime.now() + datetime.timedelta(weeks=3)) # 三周后
print(datetime.datetime.now() + datetime.timedelta(weeks=-3)) # 三周前
print(datetime.datetime.now() + datetime.timedelta(days=-3)) # 三天前
print(datetime.datetime.now() + datetime.timedelta(days=3)) # 三天后
print(datetime.datetime.now() + datetime.timedelta(hours=5)) # 5小时后
print(datetime.datetime.now() + datetime.timedelta(hours=-5)) # 5小时前
print(datetime.datetime.now() + datetime.timedelta(minutes=-15)) # 15分钟前
print(datetime.datetime.now() + datetime.timedelta(minutes=15)) # 15分钟后
print(datetime.datetime.now() + datetime.timedelta(seconds=-70)) # 70秒前
print(datetime.datetime.now() + datetime.timedelta(seconds=70)) # 70秒后
current_time = datetime.datetime.now()
# 可直接调整到指定的 年 月 日 时 分 秒 等
print(current_time.replace(year=1977)) # 直接调整到1977年
print(current_time.replace(month=1)) # 直接调整到1月份
print(current_time.replace(year=1989,month=4,day=25)) # 1989-04-25 18:49:05.898601
# 将时间戳转化成时间
print(datetime.date.fromtimestamp(1232132131)) # 2009-01-17
random模块 / 随机模块
import random
#随机小数
random.random() # 大于0且小于1之间的随机小数
print(random.random()) # 0.7664338663654585
random.uniform(1,3) #大于1小于3的随机小数
print(random.uniform(1,3)) # 1.6270147180533838
#随机整数
random.randint(1,5) # 大于等于1且小于等于5之间的整数
random.randrange(1,10,2) # 大于等于1且小于10之间的奇数 (可设置步长 例 : 2)
#随机选择一个返回
random.choice([1,'23',[4,5]]) # #1或者23或者[4,5]
#随机选择多个返回,返回的个数为函数的第二个参数
random.sample([1,'23',[4,5]],2) # 列表元素任意2个组合
# [[4, 5], '23']
#打乱列表顺序
item=[1,3,5,7,9]
random.shuffle(item) # 打乱顺序 # [5, 1, 3, 7, 9]
#随机字母
v1=random.randint(65,90) # Ascall码中对应A-Z的是65-90
v2=random.randint(97, 122) # # Ascall码中对应a-z的是97-122
生成随机验证码
import random
def v_code():
code = ''
for i in range(5):
num=random.randint(0,9)
alf=chr(random.randint(65,90)) # Ascall码中对应A-Z的是65-90
alf_1=chr(random.randint(97, 122)) # Ascall码中对应a-z的是97-122
add=random.choice([num,alf])
code="".join([code,str(add)])
return code
print(v_code())
logging日志
工作日志四大分类
系统日志
- 记录服务器的一些重要信息 / 监控系统 /cpu温度 / 网卡流量 / 重要的硬件的一些指标 / 运维人员经常使用的 / 记录运维人员的一些操作指令 et
网站日志
- 访问异常 / 卡顿 / 网站一些板块受欢迎程度 / 访问量 / 点击率 / 蜘蛛爬取次数 et
辅助开发日志
- 开发人员在开发项目中利用日志进行排错 排除一些避免不了的错误(记录) / 辅助开发
记录用户信息日志
- 用户的消费习惯 / 新闻偏好 et 数据库解决
日志格式
- 一般都是开发者使用的
默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。
low版(简易版)
- 缺点:文件与屏幕输入只能二选一
# 屏幕打印
import logging
logging.basicConfig(level=logging.DEBUG) # 相当于 logging.basicConfig(level = 10) / 基本配置
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
'''
DEBUG:root:debug message
INFO:root:info message
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message'''
# 如不限制告警级别 / logging.basicConfig(level = 10)
# 打印结果 / 默认告警级别为 warning
'''
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message'''
# 输出到文件
import logging
logging.basicConfig(
# level=logging.DEBUG, # 默认是只显示大于等于WARNING级别的日志
level=30, # 限制从 30 处开始记入文件(日志文件后缀.log)
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
filename=r'test.log',) # 文件叫'test.log',format里前面是限定条件 / 格式 ,后面是文件名
logging.debug('调试模式') # 10
logging.info('正常模式') # 20
logging.warning('警告信息') # 30 =======
logging.error('错误信息') # 40
logging.critical('严重错误信息') # 50
标配版(标准版)
import logging
#创建一个logging对象
logger = logging.getLogger()
#创建一个文件对象 / 输出到文件的文件名
fh = logging.FileHandler("标配版.log",encoding = "utf-8")
#创建一个屏幕对象
sh = logging.StreamHandler()
#配置显示格式 (都可以调数据) 执行时间 / 文件名 / 行数 / 警告级别名
formatter1 = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') # 相对数据较多格式
formatter2 = logging.Formatter('%(asctime)s %(message)s') # 极简格式
fh.setFormatter(formatter1)
sh.setFormatter(formatter2)
logger.addHandler(fh) # 绑定文件句柄
logger.addHandler(sh) # 绑定屏幕输出
#总开关 / 先设定总开关 因为默认显示级别为30
logger.setLevel(10) # 总设置 限定显示或打印级别
fh.setLevel(10) # 设置文件显示级别
sh.setLevel(40) # 设置屏幕输出级别
logger.debug("debug message")
logger.info("info message")
logger.warning("warning mesaage")
logger.error("error message")
logger.critical("critical message")
参数
logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:
filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为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用户输出的消息
旗舰版 ***
- (真正项目中使用的,Django项目) 项目中常用
"""
logging配置
"""
import os
import logging.config
# 定义三种日志输出格式 开始
# #1 standard_format 复杂参数格式
# 线程名 # 线程id # 任务 id
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]'
'[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
# #2 simple_format 简单参数格式
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
# #3 id_simple_format 极简参数格式
id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
# 定义日志输出格式 结束
logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录
logfile_name = 'all2.log' # log文件名
# 如果不存在定义的日志目录就创建一个
if not os.path.isdir(logfile_dir):
os.mkdir(logfile_dir)
# log文件的全路径
logfile_path = os.path.join(logfile_dir, logfile_name)
# log配置字典 (自己可以自定义设计字典配置)
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {},
'handlers': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
#打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': logfile_path, # 日志文件
'maxBytes': 1024*1024*5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
},
},
}
def load_my_logging_cfg(a): #可以传参
logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置
logger = logging.getLogger(__name__) # 生成一个log实例
logger.info('It works!') # 记录该文件的运行状态
# 或者
logger.info(a) # a 为传入参数 可以是自定义格式化内容 被调用时直接使用函数加传参的方式写入或打印到屏幕
# 作为脚本使用
if __name__ == '__main__':
load_my_logging_cfg()
logger配置文件
注意注意注意:
#1、有了上述方式我们的好处是:所有与logging模块有关的配置都写到字典中就可以了,更加清晰,方便管理
#2、我们需要解决的问题是:
1、从字典加载配置:logging.config.dictConfig(settings.LOGGING_DIC)
2、拿到logger对象来产生日志
logger对象都是配置到字典的loggers 键对应的子字典中的
按照我们对logging模块的理解,要想获取某个东西都是通过名字,也就是key来获取的
于是我们要获取不同的logger对象就是
logger=logging.getLogger('loggers子字典的key名')
但问题是:如果我们想要不同logger名的logger对象都共用一段配置,那么肯定不能在loggers子字典中定义n个key
'loggers': {
'l1': {
'handlers': ['default', 'console'], #
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
},
'l2: {
'handlers': ['default', 'console' ],
'level': 'DEBUG',
'propagate': False, # 向上(更高level的logger)传递
},
'l3': {
'handlers': ['default', 'console'], #
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
},
}
#我们的解决方式是,定义一个空的key
'loggers': {
'': {
'handlers': ['default', 'console'],
'level': 'DEBUG',
'propagate': True,
},
}
这样我们再取logger对象时
logging.getLogger(__name__),不同的文件__name__不同,这保证了打印日志时标识信息不同,但是拿着该名字去loggers里找key名时却发现找不到,于是默认使用key=''的配置
如何拿到logger对象的详细解释
collections模块
namedtuple: 生成可以使用名字来访问元素内容的tuple
# 但是,看到(1, 2),很难看出这个tuple是用来表示一个坐标的。 这时,namedtuple就派上了用场:
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
print(p) # Point(x=1, y=3)
print(p.y) # 2
print(p.x) # 1
print(p[0]) # 1
print(p[1]) # 2
# 具象化字典,让字典更有意义
deque : 双端队列,可以快速的从另外一侧追加和推出对象
- deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈
- deque除了实现list的
append()
和pop()
外,还支持appendleft()
和popleft()
,这样就可以非常高效地往头部添加或删除元素。
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x') # 默认添加是从尾部添加
print(q) # deque(['a', 'b', 'c', 'x'])
q.appendleft('y')
print(q) # deque(['y', 'a', 'b', 'c', 'x'])
deque(['y', 'a', 'b', 'c', 'x'])
Counter: 计数器,主要用来计数 类似count ***
Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似。
from collections import Counter
c = Counter('abcdeabcdabcaba')
print(c)
输出:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})
OrderedDict: 有序字典
- 使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。
- 如果要保持Key的顺序,可以用OrderedDict
OrderedDict
的Key会按照插入的顺序排列,不是Key本身排序
from collections import OrderedDict
d = dict([('a', 1), ('b', 2), ('c', 3)])
d # dict的Key是无序的 {'a': 1, 'c': 3, 'b': 2}
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# od# OrderedDict的Key是有序的
print(d)
print(OrderedDict([('a', 1), ('b', 2), ('c', 3)]))
od = OrderedDict()
od['z'] = 1
od['y'] = 2
od['x'] = 3
print(od.keys()) # 按照插入的Key的顺序返回 odict_keys(['z', 'y', 'x'])
print(od.values()) # odict_values([1, 2, 3])
defaultdict: 带有默认值的字典
# 有如下值集合 [11,22,33,44,55,66,77,88,99,90...],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。
# 即: {'k1': 大于66 , 'k2': 小于66}
常规字典解决办法
li = [11,22,33,44,55,77,88,99,90]
result = {}
for row in li:
if row > 66:
if 'key1' not in result:
result['key1'] = []
result['key1'].append(row)
else:
if 'key2' not in result:
result['key2'] = []
result['key2'].append(row)
print(result)
defaultdict字典解决方法
from collections import defaultdict
values = [11, 22, 33,44,55,66,77,88,99,90]
my_dict = defaultdict(list)
for value in values:
if value>66:
my_dict['k1'].append(value)
else:
my_dict['k2'].append(value)
带默认值的字典 / defaultdict
使用dict
时,如果引用的Key不存在,就会抛出KeyError
。如果希望key不存在时,返回一个默认值,就可以用defaultdict
:
from collections import defaultdict
dd = defaultdict(lambda: 'N/A') # lambda里可设置其他类型默认值
dd['key1'] = 'abc'
dd['key1'] # key1存在
'abc'
dd['key2'] # key2不存在,返回默认值
'N/A'
re模块
正则表达式
从一大堆字符串中 , 找出你想要的字符串
在对于你想要的这个字符串进行一个精确地描述
爬虫
方法太多
匹配规则特别多
import re
# re.findall()
# 正则表达式: 从一大堆字符串中,找出你想要的字符串.
# 在于对你想要得这个字符串进行一个精确地描述.
# 单个字符匹配
# =============
# W与w
# w 数字字母下划线中文
# W 非数字字母下划线中文
# print(re.findall('w', '太白jx 12*() _'))
# print(re.findall('W', '太白jx 12*() _'))
# =============
# s与S
# s 匹配的 空格
# S 匹配的 非空格
# print(re.findall('s','太白barry*(_
'))
# print(re.findall('S','太白barry*(_
'))
# =============
# d与D
# d 匹配所有的数字
# D 非匹配所有的数字
# print(re.findall('dd','1234567890 alex *(_'))
# print(re.findall('D','1234567890 alex *(_'))
# =============
# A ^从开头开始匹配
# print(re.findall('Ahello','hello hello 太白 hell'))
# print(re.findall('^hello','hello hello 太白 hell'))
# =============
# ,从结尾开始匹配
# $从结尾开始匹配
# print(re.findall('fjkdsla太白金星','fjkdsla太白金星'))
# print(re.findall('金星$','fjkdsla太白金星'))
# =============
#
# print(re.findall('
','fdsak
fkjdlas
'))
# print(re.findall(' ','fdsak
fkjdlas
'))
# 元字符匹配
# . ? * + {m,n} .* .*?
# . 匹配任意一个字符
# 如果匹配成功光标则移到匹配成功的最后的字符
# 如果匹配未成功光标则向下移动一位再次匹配
# print(re.findall('a.b','aaabbb'))
# ? 匹配0个或者1个由左边字符定义的片段。
# print(re.findall('a?b', 'ab aab'))
# print(re.findall('a?b', 'sb ab aabb'))
# * 匹配0个或者多个左边字符表达式。 满足贪婪匹配
# print(re.findall('a*b','aaab ab b'))
# # print(re.findall('a*b','aasab ab b'))
# + 匹配1个或者多个左边字符表达式。 满足贪婪匹配
# print(re.findall('a+b','aaab ab b'))
# {m,n} 匹配m个至n(n能取到)个左边字符表达式。 满足贪婪匹配
# print(re.findall('a{1,5}b', 'ab aab aaab aaaab aaaaaab aaaaabb'))
# .* 贪婪匹配 从头到尾.
# print(re.findall('a.*b','aab abbliye aaab abbb aa#b'))
# print(re.findall('a.*b','asb abbliyeaaab
abbb aa#y',re.DOTALL)) # a...................b
# .*? 此时的?不是对左边的字符进行0次或者1次的匹配,
# 而只是针对.*这种贪婪匹配的模式进行一种限定:告知他要遵从非贪婪匹配 推荐使用!
# 0个或者多个
# print(re.findall('a.*?b','ab a#bbbbbb aaab'))
# print(re.findall('a.*b','a#bbbbbb'))
# print(re.findall('a.*?b','a#bbbbbb'))
# []
# print(re.findall('a[abc]b', 'aab abb acb adb afb a_b'))
# print(re.findall('a[abc][bd]b', 'aabb aaabc abd acdbb'))
# print(re.findall('a[0-9]b', 'a1b a3b aeb a*b arb a_b'))
# print(re.findall('a[a-z]b', 'a1b a3b aeb a*b arb a_b'))
# print(re.findall('a[A-Z]b', 'aAb a3b aEb a*b aRb a_b'))
# print(re.findall('a[a-zA-Z]b', 'aab a3b aAb a*b aTb a_b'))
# 当你想匹配 - 时,要把它放在[]里面的最前面或者最后面
# print(re.findall('a[-*$]b', 'a-b a$b a)b a*b '))
# ^ 在中括号里面最前面代表取反
# print(re.findall('a[0-9]b', 'a1b a$b a5b a*b '))
# print(re.findall('a[*^)]b', 'a^b a$b a5b a*b '))
# 'alex_sb wusir_sb ritian_sb 太白_nb yuanbao_sb'
s = 'alex_sb wusir_sb ritian_sb 太白_nb yuanbao_sb dsb_sb'
# print(re.findall('w+_sb',s))
# # 'alex_sb wusir_sb ritian_sb 太白_nb yuanbao_sb'
# # ()
# print(re.findall('(w+)_sb',s))
# |
# print(re.findall('alex|太白|wusir', 'alex太白wusiraleeeex太太白odlb'))
# # () 分组里面加了?: 将全部的内容给我返回回来,而不是将组内的内容返回
# print(re.findall('companies|company',
# 'Too many companies have gone bankrupt, and the next one is my company')) # ['ies', 'y']
# printy companies have gone bankrupt, and the next one is my company'))(re.findall('compan(?:ies|y)',
# # 'Too man
# search match
import re
# 找到第一个符合条件的字符串就返回,返回一个对象,通过对象.group()
# ret = re.search('sb|alex', 'alex sb sb barry 日天')
# ret = re.search('alex', 'fdsjkfd fjdsklalex gfdlgjfdlgjfggfjlgjfkdl')
# # # print(ret)
# # # print(ret.group())
#
# # 从字符串开头匹配,如果以符合条件的字符串开头则返回,否则返回None
# ret = re.match('alex', 'alexfdskfd fjdsklalex gfdlgjfdlgjfggfjlgjfkdl')
# print(ret)
# print(ret.group())
# split
# s1 = 'alex;wusir,太白 吴超~宝元'
# import re
# print(re.split('[;, ~]',s1))
import re
# print(re.sub('barry', '太白', 'barry是最好的讲师,barry就是一个普通老师,请不要将barry当男神对待。'))
# obj = re.compile('d{2}')
# # print(obj.search('fdsa12fds435454').group())
# print(obj.findall('fjdskalf2134fkjsd3245fdjsl545'))