day09
序列化之json
之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。
为什么要序列化?
1:持久保存状态
需知一个软件/程序的执行就在处理一系列状态的变化,在编程语言中,'状态'会以各种各样有结构的数据类型(也可简单的理解为变量)的形式被保存在内存中。
内存是无法永久保存数据的,当程序运行了一段时间,我们断电或者重启程序,内存中关于这个程序的之前一段时间的数据(有结构)都被清空了。
在断电或重启程序之前将程序当前内存中所有的数据都保存下来(保存到文件中),以便于下次程序执行能够从文件中载入之前的数据,然后继续执行,这就是序列化。
具体的来说,你玩使命召唤闯到了第13关,你保存游戏状态,关机走人,下次再玩,还能从上次的位置开始继续闯关。或如,虚拟机状态的挂起等。
2:跨平台数据交互
序列化之后,不仅可以把序列化后的内容写入磁盘,还可以通过网络传输到别的机器上,如果收发的双方约定好实用一种序列化的格式,那么便打破了平台/语言差异化带来的限制,实现了跨平台数据交互。
反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
序列化: 就是把内存里的数据结构保存下来。
json格式字符串特点:
json 只支持有限的数据类型 字典 列表 数字类型
json 字典的key只能是字符串
json引号只能是双引号
python的None转换过来是null,也是字符串格式
示例:
1 import json
2
3 dic={'name':'alvin','age':23,'sex':'male'}
4 print(type(dic))#<class 'dict'>
5
6 j=json.dumps(dic)
7 print(type(j))#<class 'str'>
8
9
10 f=open('序列化对象','w')
11 f.write(j) #-------------------等价于json.dump(dic,f)
12 f.close()
13 #-----------------------------反序列化<br>
14 import json
15 f=open('序列化对象')
16 data=json.loads(f.read())# 等价于data=json.load(f)
注意:
import json
#dct="{'1':111}"#json 不认单引号
#dct=str({"1":111})#报错,因为生成的数据还是单引号:{'one': 1}
dct='{"1":"111"}'
print(json.loads(dct))
#conclusion:
# 无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads
dumps多个数据
需要连续dump,使用dumps
10个字典
分别对每一个字典进行dumps转成字符串
写到文件+
反序列化的时候
先按行读"{}
"
去掉换行符之后使用loads反序列化
多个数据示例:
a = [1,2]
b = [1,2,3]
c = [1,2,3,4]
msg = ''
msg += json.dumps(a) + '
'
msg += json.dumps(b) + '
'
msg += '{}
'.format(json.dumps(c))
with open('a.json',mode='w') as f:
f.write(msg)
with open('a.json') as f:
for i in f:
obj = json.loads(i.strip())
print(obj)
序列化pickle
优点:支持所有python数据类型;缺电:不能跨平台
结果: pickle是bytes类型;json是字符串类型;
pickle多个数据
不能用for循环读取,是字节类型,json可以.strip() 去掉换行符,pickle不行;
file = open('pickle_file','rb')
while True:
try:
print(pickle.load(file))
except EOFError:
break
示例:
1 import pickle
2
3 dic={'name':'alvin','age':23,'sex':'male'}
4
5 print(type(dic))#<class 'dict'>
6
7 j=pickle.dumps(dic)
8 print(type(j))#<class 'bytes'>
9
10
11 f=open('序列化对象_pickle','wb')#注意是w是写入str,wb是写入bytes,j是'bytes'
12 f.write(j) #-------------------等价于pickle.dump(dic,f)
13
14 f.close()
15 #-------------------------反序列化
16 import pickle
17 f=open('序列化对象_pickle','rb')
18
19 data=pickle.loads(f.read())# 等价于data=pickle.load(f)
20
21
22 print(data['age'])
日志 logging
日志级别
CRITICAL = 50 #FATAL = CRITICAL
ERROR = 40
WARNING = 30 #WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0 #不设置
默认级别为warning,默认打印到终端
日志模块的四种角色
1. logger对象: 产生日志
2. filter对象: 日志过滤,几乎不用
3. Handler对象:接收logger传过来的对象,进行日志格式化,可以打印到终端和文件。
4. Formatter对象:日志格式
设置日志级别
handler可以设置(终端、文件)
logger对象也可以设置,logger卡后边的级别。
当前模块反射
from conf import settings
if hasattr(sys.modules[__name__],'settings'):
print(getattr(sys.modules[__name__],'settings'))
导入这个模块之后,就可以搜索到了。这是搜索当前导入的模块;
看这个模块中有没有后边的'settings',是看在不在globals()的内容里;全局作用域里有没有。
项目中的应用:
"""
logging配置
"""
import os
import logging.config
# 定义三种日志输出格式 开始
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]'
'[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
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():
logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置
logger = logging.getLogger(__name__) # 生成一个log实例
logger.info('It works!') # 记录该文件的运行状态
if __name__ == '__main__':
load_my_logging_cfg()
hashlib模块
import hashlib
def md5(name,pwd):
hash_obj = hashlib.md5(name.encode('utf-8')) # 加盐
hash_obj.update(pwd.encode('utf-8')) # 生成加密
pwd = hash_obj.hexdigest() # 打印加密,digest消化的意思
return name,pwd
ret = md5('alex','fdsa')
print(ret)
# 字符串是unicode编码,编码生成bytes类型。
subprocess模块
和os.system的区别:
把结果先存到一个地方,用的时候去取
正确结果
import subprocess
import time
obj=subprocess.Popen('tasklist',shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
print(obj)
print('第1次:',obj.stdout.read())
# print('第2次:',obj.stdout.read()) 第二次就没有东西了,因为第一次取完了
print('---->主')
print(obj.stdout.read().decode('gbk'))
错误结果
obj=subprocess.Popen('tssssasklist',shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
print(obj.stdout.read())
print(obj.stderr.read().decode('gbk'))
一个程序的结果,丢给另外一个程序执行:
obj1=subprocess.Popen('tasklist',shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
obj2=subprocess.Popen('findstr python',shell=True,
stdin=obj1.stdout,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
print(obj2.stdout.read())
configparser 模块
import configparser
config=configparser.ConfigParser()
config.read('my.ini') # 读到内存
print(config.sections())
print(config.options('mysqld')) # 查看section是mysqld的配置项
print(config.get('mysqld','charater-server-set')) # 查看配置项是charater-server-set的值
判断有没有配置项
if config.has_option('mysqld','aaa'):
print(config.get('mysqld','aaa'))
正常get拿到的都是字符串类型
print(config.getboolean('mysqld','skip-grant-table'))
print(config.getint('mysqld','port'))
print(config.getfloat('mysqld','port'))
修改
print(config.getboolean('mysqld','skip-grant-table'))
print(config.getint('mysqld','port'))
print(config.getfloat('mysqld','port'))
config.add_section('egon')
config.set('egon','name','egon')
config.set('egon','age','18')
config.set('client','password','alex3714')
config.write(open('my.ini','w',encoding='utf-8')) # 在内存里对这个对象修改,这个对象已经是所有的值,所以只能是w模式覆盖