第六章 常用模块(5):python常用模块(序列化模块:pickle,json,shelve,xml)

6.3.7 序列化模块 (pickle,json,shelve,xml)

文件写入,数据传输时,我们都是以字符串形式写入的(因为字符串可以encode成bytes)。
那其他类型(比如字典,列表等)想写入文件时如何处理呢?

这时候我们就需要一种操作,叫做序列化。

+那什么是序列化呢?
+ 把内存数据(unicode)转成字符(bytes类型),叫做序列化。
>序列化用于存入硬盘或者网络传输等
+ 把字符转成内存数据,叫反序列化。

简单点说,就是: 序列化: 其他类型数据 --> 字符类型
反序列化: 字符类型 --> 其他数据类型
>字符类型:str, bytes or bytearray

  • 可以序列化,反序列化的模块有以下2种:
    • pickle
    • json

      这两种模块的用法完全一样

用eval()方法也可以达到效果。那有什么区别呢?

1. json模块 (.json文件)

序列化成字符串类型

  • json特点
    • 需要用open打开文件再处理
    • 用'w','r'等类型打开文件进行
    • 序列化成字符串类型
    • 文件扩展名用.json
  • json与pickle的区别:
    • json能识别的数据类型:str,int,tuple,list,dict
    • json可以跨平台使用
import json
  1. json.dump(obj,fp,skipkeys,...)
    将obj序列化成字符串类型,并写入文件对象fp中。返回None

    json.dumps():将数据转成字符串并存到内存 这个一般用在:1.网络数据传输 2.跨平台,跨语言的数据交互

  2. json.load(fp,cls,...)
    读取json序列化的文件对象fp,反序列,返回反序列后的数据

    json.loads():读取dumps的数据,并反序列
import json

data = {'name': 'Alex', 'age': 22, 'salary': [1, 2, 3]}

# d1 = json.dumps(data)  # 把data序列化。 ->序列化后转为str类型
# d2 = json.loads(data)  # 把data反序列化。 ->反序列化转成相应数据类型(字典,列表等)

with open('test.json','w') as f:  # 一般json序列化的文件扩展名用.json

    d1 = json.dump(data,f)  # 把data序列化,并且写入文件对象f中。因为返回None,所以d1是None

with open('test.json','r') as f:

    d2 = json.load(f)  # 把文件对象f的数据反序列化,返回给d2
    

拓展:数据交互方式有2种:json,xml json 可读性,数据大小 都优越于 xml
Azure的旧环境用的xml,新环境用的json

2. pickle模块 (.pkl文件)

序列化成bytes类型。

注意:因为序列化成bytes类型,所以文件的读写要用rb,wb等模式来进行!

  • pickle特点
    • 需要用open打开文件再处理
    • 用'wb','rb'等类型打开文件进行
    • 序列化成bytes类型
    • 文件扩展名用.pkl
  • pickle与json的区别:
    • pickle支持python里所有的数据类型(比如函数,类什么的都可以)

      所以python使用的文件,不论内容时什么我们都可以pickle

    • pickle只能在python里使用

import pickle
  1. pickle.dump(obj,file,protocol,...)
    将obj序列化成bytes类型,并写入file文件,如果没有会创建文件。返回None

  2. pickle.load(file,...)
    读取json序列化的文件对象fp,反序列,返回反序列后的数据

    .loads():读取dumps的数据,并反序列
import pickle

data = [1, 2, 3]

d1 = pickle.dumps(data)  # 把data序列化。 ->序列化后转为bytes类型
d2 = pickle.loads(d1)  # 把data反序列化。 ->反序列化转成相应数据类型

with open('test.pkl', 'wb') as f:  # 一般pickle序列化的文件扩展名用.pkl
    pickle.dump(data, f)

with open('test.json', 'rb') as f:
    d = pickle.load(f)

print(type(d1))
print(type(d2))
print(d)
3. shelve模块 ()

shelve对pickle进行了封装,并且可以多次dump和load

  • 区别及特点:
    • pickle
      • 一个文件只能dump一次(因为dump多次容易混乱)
      • 用open()函数打开文件
    • shelve
      • 可以对文件多次dump,load
      • 用shelve模块的.open()方法打开文件
      • 数据的结构类似dict
      • 可以直接用类似处理dict的方法处理数据

序列化:

import shelve

f = shelve.open('shelve_test')  # 打开(没有就创建)文件。会创建多个文件。可以跟open一样用with

list1 = ['a','b','c','d']
dict1 = {'key1':'abcd','key2':'1234'}

f['li1'] = list1  # 持久化列表 --> 就是写入序列化文件中,并且有个名字是'li1'
f['d1'] = dict1  # 持久化字典 --> 就是写入序列化文件中,并且有个名字是'd1'

f.close()  # 关闭保存

反序列化:

import shelve

with shelve.open('shelve_test') as f:
    print(f['li1'])  # 直接调用li1的数据
    print(f['d1'])  # 直接调用d1的数据

    # shelve打开的文件对象构造类似字典,可以使用字典的方法:
    print('get li1:', f.get('li1'))  # 有get()方法
    i = f.items()  # 有items()方法。 注意:这个i指向f.items()的内存地址,f.items()的值变化,i也会随之变化
    print(id(i))
    print(i)  # 返回值是shelve对象类型,不能直接使用
    print(list(i))  # 所以需要list()转换一下才可以看到内容

    f['li2'] = ['aaaa','bbbb']  # 可以追加新的数据
    print(list(i))

    f.pop('li2')  # 可以删除
    print(list(i))

    f['li1'] = [2, 3, 4, 5]  # 可以直接修改某个数据的整个内容
    print(list(i))

    f['li1'][1] = 'b'  # 但是不能改其中的一部分内容(字典可以)
    print(list(i))  # 结果并没有改变
    print(id(i))
4. xml模块 (.xml)

作用和json一样,是json出现之前很常用的序列化模块。 构造也和字典类似。用<>来定义数据。

  1. 读取xml文档内容:

    # 读取数据
    import xml.etree.ElementTree as ET
    
    tree = ET.parse('test.xml')  # 打开xml文件,返回xml对象
    root = tree.getroot()  # 取数据最上级key
    # print(dir(root))  # 可以显示数据的keys
    print(root.tag)
    
    # 遍历文档
    for child in root:
        print(child.tag, child.attrib)
        for i in child:
            print(i.tag, i.attrib)
    
    # 只遍历year节点
    for node in root.iter('year'):
        print(node.tag, node.text)
  2. 修改和删除xml文档内容:

    # 修改数据
    import xml.etree.ElementTree as ET
    
    tree = ET.parse('test.xml')
    root = tree.getroot()  # 取数据最上级key
    
    # 修改
    for node in root.iter('year'):
        new_year = int(node.text) + 1  # 取数据并计算
        node.text = str(new_year)  # 把值转成str并赋值给原来的内容
        node.set('update', 'yes')  # 设置属性和值
    
    tree.write('test.xml')  # 内容写入文件
    # 删除数据
    import xml.etree.ElementTree as ET
    
    tree = ET.parse('test.xml')
    root = tree.getroot()  # 取数据最上级key
    
    # 删除node
    for country in root.findall('country'):
        rank = int(country.find('rank').text)
        if rank > 50:
            root.remove(country)
    
    tree.write('output.xml')  # 结果写到一个新文件里    
  3. 创建xml文件
    ```python
    # 创建xml文件
    import xml.etree.ElementTree as ET

    root = ET.Element('namelist') # 创建名为namelist的根(root)

    name1 = ET.SubElement(root,'name',attrib={'enrolled':'yes'}) # 名称为'name'的数据放在'root'的节点上,属性设为{'enrolled':'yes'}
    age = ET.SubElement(name1,'age',attrib={'checked':'no'}) # 名称为'age'的数据放在name1的节点上,属性设置为 {'checked':'no'}
    sex = ET.SubElement(name1,'sex') # 名称为'sex'的数据放在name1的节点上
    sex.text = '33' # sex的值设为'33'

    name2 = ET.SubElement(root,'name',attrib={'enrolled':'no'}) # 名称为'name'的数据放在'root'的节点上,属性设为{'enrolled':'yes'}
    age = ET.SubElement(name2,'age') # 名称为'age'的数据放在name2的节点上
    age.text = '19' # age的值设为'19'

    et = ET.ElementTree(root) # 生成文档对象
    et.write('test.xml', encoding='utf-8', xml_declaration=True) # xml_declaration是要不要加版本号声明

    ET.dump(root)
    ```

猜你喜欢

转载自www.cnblogs.com/py-xiaoqiang/p/11110871.html