内置模块

内置模块

序列化模块(常用)

  • 本质就是将一种数据结构(如字典、列表)等转换成一个特殊的序列(特殊的字符串或者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'))


原文地址:https://www.cnblogs.com/fanxss/p/11091454.html