其他分享
首页 > 其他分享> > 17--常用模块02:json、猴子补丁、configparse、hashlib、subprocess

17--常用模块02:json、猴子补丁、configparse、hashlib、subprocess

作者:互联网

1.json&pickle模块

# 0.eval内置方法可以将一个字符串转成python对象
    eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值
    
    缺点:eval方法是有局限性的,对于特殊类型,识别不了
    
    import json
    x="[null,true,false,1]"
    print(eval(x))  # 报错,无法解析null类型,而json就可以
    print(json.loads(x))


# 1.什么是序列化&反序列化
  序列化指的是把内存的数据类型转成一个特定的格式
       该格式的内容可用于存储或传输给其他平台使用

  内存中的数据类型--->序列化--->特定的格式(json格式或者pickle格式)
  内存中的数据类型<---反序列化<---特定的格式(json格式或者pickle格式)

  土办法:
    将字典存储到硬盘中:
  	{'aaa':111}--->序列化str({'aaa':111})--->"{'aaa':111}" 
    读取硬盘中数据,转化为字典
  	{'aaa':111}<---反序列化eval("{'aaa':111}")<---"{'aaa':111}"
    
  Python中叫pickling,其他语言被称之为serialization,marshalling,flattening等等

    
# 2.为何要序列化
  序列化得到结果=》特定的格式的内容有两种用途
  1.可用于存储=》用于存档
  2.传输给其他平台使用=》跨平台数据交互
       python                 java
        列表     特定的格式      数组

  强调:
      针对用途1:可是一种专用的格式==》pickle   # 只有python可以识别
      针对用途2:应该是一种通用、能够被所有语言识别的格式==》json

1.1 json模块

若是给其他语言使用(跨平台数据交互),就序列化成json格式

# 3.如何序列化与反序列化

# 示范1
import json
# 序列化
json_res=json.dumps([1,'aaa',True,False])
print(json_res,type(json_res))  # "[1, "aaa", true, false]"

# 反序列化
l=json.loads(json_res)
print(l,type(l))


# 示范2:
# 序列化的结果写入文件的复杂方法
# ---->先序列化字符串,再单纯的写入文件
json_res=json.dumps([1,'aaa',True,False])
with open('test.json',mode='wt',encoding='utf-8') as f:
    f.write(json_res)

# 将序列化的结果写入文件的简单方法                 (使用这个)
# --->直接序列化成文件格式
with open('test.json',mode='wt',encoding='utf-8') as f:
    json.dump([1,'aaa',True,False],f)

# 从文件读取json格式的字符串进行反序列化操作的复杂方法
with open('test.json',mode='rt',encoding='utf-8') as f:
    json_res=f.read()
    l=json.loads(json_res)
    print(l,type(l))
    
# 从文件读取json格式的字符串进行反序列化操作的简单方法 (使用这个)
with open('test.json',mode='rt',encoding='utf-8') as f:
    l=json.load(f)
    print(l,type(l))

    
# 总结:
json.dumps(str)     字符串 --> 序列化 --> json字符串
json.loads(json)    json字符串 --> 反序列化 --> 字符串

json.dump(str,f)    序列化,并存到f文件中
json.load(f)        从f文件中,反序列化

json格式

1.2 json 补充

# json验证: json格式兼容的是所有语言通用的数据类型,不能识别某一语言所独有的类型
json.dumps({1,2,3,4,5})   # 错误,集合不能序列化 

# json强调:一定要搞清楚json格式,不要与python混淆
l=json.loads('[1, "aaa", true, false]')
l=json.loads("[1,1.3,true,'aaa', true, false]")   # json的字符串是 双引号 ""


# 了解:在python解释器2.7与3.6之后都可以json.loads(bytes类型),但唯独3.5不可以
l = json.loads(b'[1, "aaa", true, false]')
print(l, type(l))

# 故反序列文件,可以直接以bytes类型打开
with open('test.json',mode='rb') as f:
    l=json.load(f)

res=json.dumps({'name':'哈哈哈'})
print(res,type(res))
res=json.loads('{"name": "\u54c8\u54c8\u54c8"}')
print(res,type(res))

1.3 猴子补丁

# 一.什么是猴子补丁?
    属性在运行时的动态替换,叫做猴子补丁(Monkey Patch)。
    
    猴子补丁的核心就是用自己的代码替换所用模块的源代码,来源如下:
   1.这个词原来为Guerrilla Patch,杂牌军、游击队,说明这部分不是原装的
      在英文里guerilla发音和gorllia(猩猩)相似,再后来就写了monkey(猴子)
    
   2.还有一种解释是说由于这种方式将原来的代码弄乱了(messing with it),
      在英文里叫monkeying about(顽皮的),所以叫做Monkey Patch。


# 二.猴子补丁的功能(一切皆对象)
  1.拥有在模块运行时替换的功能
     例如: 一个函数对象赋值给另外一个函数对象(把函数原本执行的功能给替换了)
            
class Monkey:
    def hello(self):
        print('hello')

    def world(self):
        print('world')


def other_func():
    print("from other_func")


monkey = Monkey()
monkey.hello = monkey.world
monkey.hello()  # word
monkey.world = other_func
monkey.world()  # from other_func


# 三.monkey patch的应用场景
  如果我们的程序中已经基于json模块编写了大量代码了
  发现有一个模块ujson比它性能更高,但用法一样
  我们肯定不会想所有的代码都换成ujson.dumps或者ujson.loads
  那我们可能会想到这么做 import ujson as json
  但是这么做的导入该模块的文件都需要都重新修改一下,维护成本依然很高
  此时我们就可以用到猴子补丁了,只需要在入口处(程序首次进入的地方,一般是启动文件)加上:
    
import json
import ujson

def monkey_patch_json():
    json.__name__ = 'ujson'
    json.dumps = ujson.dumps
    json.loads = ujson.loads

monkey_patch_json()  
# 之所以在入口处加,是因为模块在导入一次后,后续的导入便直接引用第一次的成果


# 实际场景:
  1.用新模块替换原来的模块
  2.丰富模块的功能, 除了继承之外也可以考虑用Monkey Patch

好处:
  采用猴子补丁之后,如果发现ujson不符合预期,那也可以快速撤掉补丁
缺点:
  MonkeyPatch带了便利的同时也有搞乱源代码的风险!

1.4 pickle模块

若是python自己使用(数据存档),就序列化成pickle格式

import pickle
# 序列化
res=pickle.dumps({1,2,3,4,5})
print(res,type(res))   # pickle模块序列化是bytes类型

# 反序列化
s=pickle.loads(res)
print(s,type(s))

# 总结:
pickle.dumps(str)     字符串 --> 序列化 --> pickle序列化bytes类型
pickle.loads(json)    pickle序列化bytes类型 --> 反序列化 --> 字符串

pickle.dump(str,f)    序列化,并存到f文件中
pickle.load(f)        从f文件中,反序列化
# python2与python3的pickle兼容性问题

# 1.在python3中,执行的序列化操作 如何兼容python2
    python2不支持protocol>2,默认python3中protocol=4
    故:python3中dump操作 应该指定protocol=2

        
# coding:utf-8
import pickle

with open('a.pkl',mode='wb') as f:
    pickle.dump('你好啊',f,protocol=2)

# python2中,反序列化才能正常使用
with open('a.pkl', mode='rb') as f:
    res=pickle.load(f)
    print(res)

2.shelve 模块(了解)

# shelve模块: 以字典的形式序列化存储 数据    shelve:书架,搁置
  shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;
  key必须为字符串,而值可以是python所支持的数据类型 

import shelve

f = shelve.open(r'sheve.txt')

# 序列化
f['stu1_info'] = {'name':'egon','age':18,'hobby'['piao','smoking','drinking']}
f['stu2_info'] = {'name':'gangdan','age':53}
f['school_info'] = {'website':'http://www.pypy.org','city':'beijing'}

# 反序列化
print(f['stu1_info']['hobby'])

f.close()

3.configparser模块

# 配置文件: 常用格式后缀 ".ini"

# 注释1
; 注释2

[section1]    # 以section:部分 来划分几个部分
k1 = v1       # option:项 '=' 或者 ':' 值
k2:v2
user=egon
age=18
is_admin=true
salary=31

[section2]
k1 = v1

3.1 读取配置文件

# 用来处理固定格式的配置文件   configparser 配置解析

import configparser

config=configparser.ConfigParser()   # 首先实例化类-对象
config.read('test.ini')   # .read()  读取配置文件 

# 1.获取sections
print(config.sections())  # ['section1', 'section2']

# 2.获取某一section下的所有options
print(config.options('section1'))  # ['k1', 'k2'...]

# 3.获取items
print(config.items('section1'))  # [('k1', 'v1'), ('k2', 'v2')...]

# 4.获取-某部分-某项的值
res=config.get('section1','user')
print(res,type(res))  # egon  str

# 5.获取-某部分-某项的值,并转化成数字格式
res=config.getint('section1','age')
print(res,type(res))  # 18  int

# 6.获取-某部分-某项的值,并转化成布尔格式
res=config.getboolean('section1','is_admin')
print(res,type(res))  # True  bool

# 7.获取-某部分-某项的值,并转化成浮点数格式
res=config.getfloat('section1','salary')
print(res,type(res))  # 31.0  float

3.2 改写配置文件

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','user'))

# 添加一个标题
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'))

4.hashlib模块

# 1.什么是哈希hash
  hash是一类算法,该算法接受传入的内容,经过运算得到一串hash值
    
  3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5算法
     
# 2.hash值的特点:
  1.只要传入的内容一样,和hash的算法一样,得到的hash值必然一样
  2.不能由hash值反解成内容
  3.不管传入的内容有多大,只要使用的hash算法不变,得到的hash值长度是一定
    好处是:不会随着传入的内容越大而扩大hash长度,节约传输空间

# 3.hash的用途
    用途1:特点2用于密码密文传输与验证
    用途2:特点1、3用于文件完整性校验

    
# 4.如何用
import hashlib

m=hashlib.md5()   # 调用hashlib库下的各种hash算法函数,也可以直接传参-->要hash的内容

m.update('hello'.encode('utf-8'))  # .update() 上传 要hash的内容 
m.update('world'.encode('utf-8'))  # 传入要hash的内容必须是 bytes类型

res=m.hexdigest() # 'helloworld'   # .hexdigest() 拿到hash值
print(res)

m1=hashlib.md5('he'.encode('utf-8'))
m1.update('llo'.encode('utf-8'))
m1.update('w'.encode('utf-8'))
m1.update('orld'.encode('utf-8'))
res=m1.hexdigest()   # 和'helloworld' hash结果一样
print(res)
md5:是32位加密


# 模拟撞库
cryptograph='aee949757a2e698417463d47acac93df'
import hashlib

# 制作密码字段
passwds=[
    'alex3714',
    'alex1313',
    'alex94139413',
    'alex123456',
    '123456alex',
    'a123lex',
]

dic={}
for p in passwds:
    res=hashlib.md5(p.encode('utf-8'))
    dic[p]=res.hexdigest()

# 模拟撞库得到密码
for k,v in dic.items():
    if v == cryptograph:
        print('撞库成功,明文密码是:%s' %k)
        break


# 提升撞库的成本=>密码加盐  (在原有密码上 加上 一段暗号,且自己定制排列组合--->再去hash)
import hashlib

m=hashlib.md5()

m.update('天王'.encode('utf-8'))
m.update('alex3714'.encode('utf-8'))
m.update('盖地虎'.encode('utf-8'))
print(m.hexdigest())


# 校验文件完整性 
	
# 文件特别大时,全部hash比对浪费时间和效率
m.update(文件所有的内容)
m.hexdigest()

# 应当随机读取几个部分的内容 进行hash值比对    
f=open('a.txt',mode='rb')
f.seek()  # 移动文件指针几个位置
res = f.read(2000) # 读取固定长度的字节
m1.update(res)

m1.hexdigest()

5.subprocess模块

# suprocess是用来执行系统命令,并查看结果的

# 原理:
  利用suprocess模块下标准输出流,标准输入流,标准错误流,
  且输出格式是bytes类型,方便我们查看调用系统命令后的结果


import subprocess

# subprocess.Popen()   对象实例化该类  
  第一个参数:'系统命令'
  shell=True : Linux系统下调用终端端口
  stdout=subprocess.PIPE :将执行系统命令的正确结果,放进PIPE管道,并给stdout
  stderr=subprocess.PIPE :把返回的错误结果放在stderr管道

obj=subprocess.Popen('echo 123 ; ls / ; ls /root',shell=True,
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE,
                 )

# 读取执行命令后的 正确结果
res=obj.stdout.read()
print(res.decode('utf-8'))

# 读取执行命令后的 错误结果
err_res=obj.stderr.read()
print(err_res.decode('utf-8'))

标签:02,configparse,hash,17,res,json,print,序列化,config
来源: https://www.cnblogs.com/Edmondhui/p/16400070.html