python常用模块2

json&pickle模块

序列化&反序列化

# 序列化
	我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling
    
# 反序列化
	将可存储或传输的数据变成内存中可识别的数据结构或对象的过程称之为反序列化

序列化的目的

#1 持久保存状态
#2 跨平台数据交互

强调

# 针对目的1:可以使用一种专门的数据格式,pickle(只有python识别)
# 针对目的2:可以使用一种通用的数据格式,json(所有变成语言都识别)

JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:

json主要方法

import json

# 序列化
res = json.dumps([1,2,3,'a'])	# res是json的字符串
# 反序列化
li = json.loads(res)			# li = [1,2,3,'a']


# 将序列化的结果写入文件的简单方法
with open('test.json', 'wt', encoding='utf-8') as f:
	json.dump([1,2,3,4'a'], f)
               
# 从文件反序列化的简单写法
with open('test.json', 'rt', encoding='utf-8') as f:
	li = json.load(f)	# li = [1,2,3,4'a']   
    
    
    
# py2.7和py3.6后都支持json.loads(bytes),但py3.5不支持字节类型

# json支持的是所有语言通用的数据类型,不能识别某一个语言的特定数据类型,如,json不识别python的结合
# json格式的字符串是双引号形式,不支持单引号。

pickle主要方法

# picke的主要使用方法的json模块的使用方法一模一样
# 不过pickle.dumps序列化之后是bytes,不是json.dumps后的str


res = pickle.dumps([1,2])   
#res: b'\x80\x04\x95\t\x00\x00\x00\x00\x00\x00\x00]\x94(K\x01K\x02e.'
li = pickle.loads(res)      
#li: [1, 2]

文件的读写,直接用rb,wb模式即可

li = [1,2,3,4]
with open('li.pkl', 'wb') as f:
    pickle.dump(li, f)

with open('li.pkl', 'rb') as f:
    print(pickle.load(f))

Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容。因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。

# pickle在py2和py3中版本兼容问题:dump操作指定参数protocol

import pickle

with open('a.pkl',mode='wb') as f:
    # 一:在python3中执行的序列化操作如何兼容python2
    # python2不支持protocol>2,默认python3中protocol=4
    # 所以在python3中dump操作应该指定protocol=2
    pickle.dump('你好啊',f,protocol=2)

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

shelve模块

shelve模块支持像字典一样操作持久化的文件。该模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型。

# 为什么用shelve模块(特别是在已有json和pickle的情况下)
使用json或者pickle持久化数据,能dump多次,但load的话只能取到最新的dump,因为先前的数据已经被后面dump的数据覆盖掉了。
如果想要实现dump多次不被覆盖,就可以想到使用shelve模块。
shelve模块可以持久化所有pickle所支持的数据类型。另外,写程序的时候如果不想用关系数据库那么重量级的去存储数据,也可以用到shelve。另外,shelve其实用anydbm去创建DB并且管理持久化对象的。
import shelve

f = shelve.open('shelve.txt')		# 初始时不能存在shelve.txt文件
f['haha'] = 'asd'
print(f.get('haha'))
for k ,v in f.items():
    print(k ,v)
f.close()

# f.keys()
# f,values()
# f.setdefault()
# f.clear()
# f.pop()
# 等等的字典对象的内置方法,f对象几乎都有

xml模块

参考海峰老师的博客


configparser模块

用于程序中配置文件的访问、修改等操作的模块

示例文件 conf.ini

#[]     注释方式1:#
;[]     注释方式2:;

[section1]
k1 = v1
k2 : v2
user = egon
age = 18
is_admin = true
salary = 31

[section2]
k1 = v1

从配置文件conf.ini中读信息

import configparser

config = configparser.ConfigParser()
config.read(r'conf.ini', encoding='utf-8')		# read()获取配置文件信息,r若存在中文需要encoding

print(config.sections())    # 获取每个每部分的标题名,列表
print(config.options('section1'))       # 获取每个标题下的所有key,列表
print(config.items('section1'))         # 获取section1标题下的所有键值对,元组列表
print(config.get('section1', 'k1'))     # 获取section1下k1对应的值,默认字符串
print(config.getint('section1', 'age')) # getint()自动将str转int
print(config.getboolean('section1', 'is_admin'))    # getboolean()自动转布尔型
print(config.getfloat('setcion', 'salary'))     # 自动转浮点型

修改配置文件conf.ini的信息

import configparser

config = configparser.ConfigParser()
config.read(r'conf.ini', encoding='utf-8')

print(config.has_section('section1'))           # 判断是否有标题section
print(config.has_option('section1', 'k1'))      # 判断在section1下存在键k1,若section1不存在也返回False

config.remove_section('section4')               # 删除标题,标题不存在不做任何操作
config.remove_option('section2', 'k2')          # 删除键值对,删除后自动去空行

config.add_section('section3')                  # 增加一个标题
config.set('section3', 'k4', 'v4')              # 标题下增加一个键值对

with open('conf.ini', 'w', encoding='utf-8') as f:      # 保存文件
    config.write(f)

自动生成配置文件

import configparser

config = configparser.ConfigParser()
# 方式1
config["DEFAULT"] = {'ServerAliveInterval': '45',
                     'Compression': 'yes',
                     'CompressionLevel': '9'}
# 方式2
config.add_section('hahaha')

# 方式3
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}

# 方式4
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022'     # mutates the parser
topsecret['ForwardX11'] = 'no'  # same here

config['DEFAULT']['ForwardX11'] = 'yes'


# 保存
with open('example.ini', 'w') as configfile:
    config.write(configfile)

hashlib模块

# hash是一种算法(3.x里整合了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512, MD5算法)
# hash算法接受传入的内容,经过运算得到一串hash值

# hash值的特点是:
	-1 只要传入的内容一样,得到的hash值必然一样
	-2 不能由hash值返解成内容
	-3 无论校验的内容有多大,得到的hash值长度是固定的(使用相同的hash算法)
# hash值的用途:
	- 用途1:特点2用于密码密文传输与验证
	- 用途2:特点1、3用于文件完整性校验

使用hash算法md5

import hashlib

m = hashlib.md5(b'hello')	# hash的数据必须是bytes类型		
m.update(b'')     		 	# 多次 update
m.update(b'world')
res = m.hexdigest()
print(res)


m = hashlib.md5(b'hello')
m.update(b'world') 			# 一次update
print(m.hexdigest())


# 多次添加数据,和一次性全部加入的数据hash后的结果是相同的。
# 利用这一点,可以实现大文件验证完整性时的快速校验(选择文件的部分做hash校验)

没有绝对安全的数据,hash算法最简单的破解方式就是:撞库破解

# 模拟撞库
import hashlib

cryptograph='aee949757a2e698417463d47acac93df'
# 制作密码字段
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

加大撞库的难度:密码加盐

import hashlib

m=hashlib.md5()
m.update('天王'.encode('utf-8'))		# 加盐部分1
m.update('alex3714'.encode('utf-8'))
m.update('盖地虎'.encode('utf-8'))		# 加盐部分2
print(m.hexdigest())				# 加盐后的密文

hashlib模块下的其他hash算法

# 其他的hash算法同md5的使用方式一样, hash后的hash值可能不一样
import hashlib
m = hashlib.sha256()				# sha256
m.update('alex3714'.encode('utf-8'))
print(m.hexdigest())	# 1e1c67170a2136ba7e18ffee2461fdbcdcf0884d9d9d005d4ab8c8733a15f8ab

hmac模块

python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密

需要注意的是:hamc 多次update和一次性update的结果不同

import hmac

h = hmac.new(b'hello', msg=b'salt', digestmod='md5')	# msg默认为空,可以设置加盐
h.update('world')
print(h.hexdigest())

subprocess模块

需要掌握的操作

import subprocess

obj = subprocess.Popen('dir', shell=True,
                 stdout=subprocess.PIPE,		# 正确的输出放在一个管道内
                 stderr=subprocess.PIPE,		# 错误的输出放在一个管道内
                 )

res = obj.stdout.read()			# 读管道内正确的输出
print(res.decode('gbk'))		# res默认是bytes,需要根据操作系统,解码成字符串

res_err = obj.stderr.read()		# 读管道内的错误输出
print(res_err.decode('gbk'))
posted @ 2020-03-31 15:27  the3times  阅读(175)  评论(0)    收藏  举报