ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-06-22 12:37:03  阅读:111  来源: 互联网

标签:02 configparse hash 17 res json print 序列化 config


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有