zoukankan      html  css  js  c++  java
  • 你知道怎么对python中的对象进行序列化吗

    介绍

    数据序列化、或持久化,就是把数据从内存刷到磁盘上。但是要保证在读取的时候还能恢复到原来的状态。像pickle和json之类的持久化模块基本上无需介绍了,这里介绍两个其他很少用但是功能很强大的模块。
    

    dbm

    '''
    在一些小型程序中,不需要关系型数据库时,可以方便的用持久字典来存储键值对,和python中的字典非常类似。而且dbm的键和值都必须是str或者bytes类型
    '''
    import dbm
     
    '''
    这里第一个参数直接传入文件名,第二个参数表示模式
    常见的模式:
    r:可读,默认就是这个模式
    w:可读可写
    但是r、w,都必须确保文件已经存在,否则报错。
     
    c:可读可写,文件不存在时会创建
    n:可读可写,但总是会创建一个新的文件,也就是说如果创建同名文件,那么之前的内容都会被清空,也就是起不到追加的效果。
     
    因此我们平常的模式一般都会选择c
     
     
    第三个参数是权限,这个在windows下基本不用,是一组用八进制表示的数字,默认是0o666,都是可读可写不可执行
    '''
    db = dbm.open("store", "c")
     
    # 打开文件之后,就可以存储值了
    # 注意key和value都必须是str或者bytes类型
    db["name"] = "satori"
    db["age"] = "16"
    db["gender"] = "f"
    db["anime"] = "东方地灵殿"
     
    # 关闭文件,将内容写到磁盘上
    db.close()
     
     
    ################################################################
    # 打开文件
    db = dbm.open("store", "c")
    print(db.keys())  # [b'name', b'age', b'gender', b'anime']
    for key in db.keys():
        print(f"key={key}, value={db[key]}")
        '''
        key=b'name', value=b'satori'
        key=b'age', value=b'16'
        key=b'gender', value=b'f'
        key=b'anime', value=b'xe4xb8x9cxe6x96xb9xe5x9cxb0xe7x81xb5xe6xaexbf'
        '''
    

    会多出来这三个文件

    shelve

    '''
     
    shelve和dbm比较类似,但是功能远比dbm强大,因为它可以持久化任意对象
    '''
    import shelve
     
    # 参数flag默认是c,因此我们只需要传入文件名就可以了,这个是自动追加在后面的
    # 也就是说我写完之后,再次打开继续写的话,只会追加不会清空
    sh = shelve.open("shelve")
     
    sh["dict"] = {"name": "satori", "age": 16}
    sh["list"] = [1, 2, 3, 4]
    sh["set"] = {1, 2, 3, 2}
     
    # 写完之后关闭文件,刷到内存里面
    # 关闭之后就无法操作了
    sh.close()
     
     
    # 下面我们就可以操作数据了,下面的代码即便写在另一个py文件里面也是可以的
    sh2 = shelve.open("shelve")
    print(sh2["dict"], sh2["dict"].keys())  # {'name': 'satori', 'age': 16} dict_keys(['name', 'age'])
    print(sh2["list"], sum(sh2["list"]))  # [1, 2, 3, 4] 10
    print(sh2["set"])  # {1, 2, 3}
    sh2.close()
     
     
    # 可以看到,拿出来的就是原生的对象,可以直接用来进行操作的。那我们看看自己定义的类可不可以呢?
    sh3 = shelve.open("shelve")
     
     
    class A:
        def __init__(self, name, age):
            self.name = name
            self.age = age
     
        @property
        def print_info(self):
            return f"my name is {self.name}, age is {self.age}"
     
     
    a = A("satori", 16)
    # 将这个类和类的一个实例对象存储进去
    sh3["A"] = A
    sh3["a"] = a
    sh3.close()
     
     
    ######################################
    sh4 = shelve.open("shelve")
     
    # sh4["A"]拿到A这个类,传入参数,调用方法
    print(sh4["A"]("mashiro", "17").print_info)  # my name is mashiro, age is 17
     
    # sh4["a"]拿到a这个实例对象,直接调用方法
    print(sh4["a"].print_info)  # my name is satori, age is 16
     
    # 我们发现依旧是可以的,说明了shelve这个模块真的很强大
    
    # 我们再来看一个例子
    import shelve
     
    sh = shelve.open("shelve")
    sh["list"] = [1, 2, 3]
    sh["str"] = "mashiro"
    sh.close()
     
    ##############################
    sh = shelve.open("shelve")
    sh["list"].append("xxxx")
    sh["str"] = "satori"
    sh.close()
     
    #######################
    sh = shelve.open("shelve")
    print(sh["list"])  # [1, 2, 3]
    print(sh["str"])  # satori
    '''
    分析结果,第一次打开文件我们创建两个键值对
    sh["list"] = [1, 2, 3]
    sh["str"] = "mashiro"
     
    第二次打开文件,修改了两个键的值
    第三次打开文件,打印。但是我们发现sh["str"]改变了,但是sh["list"]没有改变,这是为什么?
    首先sh["str"] = "satori"很好理解,但是为什么sh["list"]没有变?
    因为=,我们是直接赋值,将这一块内存里面的值给换掉,而sh["list"]我们是做append操作,这只是在原来的基础上进行修改
    shelve默认情况下是不会记录,持久化对象的修改的,除非你是创建新的对象,或者是把原来的对象给换掉
    如果是在原来的基础上(可变类型),比如列表、字典,进行添加或者删除操作,这些是不会被记录的
    所以:sh["list"]=[1, 2, 3]  sh["list"].append("xxxx")  --->sh["list"]仍是[1, 2, 3]不会是[1, 2, 3, "xxx"]
    因为shelve没有记录对象自身的修改,如果我想得到期望的结果,一种方法是把对象整体换掉
    sh["list"] = [1, 2, 3, "xxxx"],这样等于是重新赋值,是可行的。但是有时候我们不知道列表里面内容,或者列表里面的内容是一些函数、类什么的、不好写的话,该咋办呢?
    其实我们在打开文件的时候,还可以加上一个参数,叫做writeback
    '''
    
    import shelve
     
    sh = shelve.open("shelve")
    sh["list"] = [1, 2, 3]
    sh["str"] = "mashiro"
    sh.close()
     
    ##############################
    # 如果我们需要进行修改,那么加上一个writeback=True就可以了,从名字也能看出来
    # 这是会将修改的内容从新写回去
    sh = shelve.open("shelve", writeback=True)
    sh["list"].append("xxxx")
    sh["str"] = "satori"
    sh.close()
     
    #######################
    sh = shelve.open("shelve")
    print(sh["list"])  # [1, 2, 3, 'xxxx']
    print(sh["str"])  # satori
    '''
    可以看到都发生改变了,但是这个参数有缺陷,就是会有额外的内存消耗。当我们加上writeback=True的时候shelve会将我们读取的对象都放到一个内存缓存当中。
    比如说我们获取了20持久化的对象,但是我们只修改了一个,剩余的19个只是查看并没有做修改,但当我们sh.close()的时候,会将这20个对象都写回去
    因为shelve不知道你会对哪个对象进行修改,于是不管你是查看还是修改,都会放到缓存当中,然后再一次性都写回去。
    这样会造成两点:
    1.对象放到内存缓存当中,等于是重新拷贝了一份,因为我们读取文件已经到内存当中了,而shelve又把我们使用的对象放当内存的另一片空间中
    2.写入数据,我们明明只修改了一份数据,但是它把20份都重新写回去了,这样会造成性能上的问题,导致效率会降低。
    因此加不加这个参数,由具体情况决定
    '''
    

    同样也会多出来三个文件

  • 相关阅读:
    挖矿是如何产生比特币的?
    影响世界的100个管理定律
    震撼人心的战争类背景音乐
    一个美国女警的工作记录(转载
    李昌镐:苍老的青春(转载)
    博主简介
    python 中判断变量是否定义
    Reading geometries
    Writing geometries
    Accessing data using cursors
  • 原文地址:https://www.cnblogs.com/traditional/p/11111363.html
Copyright © 2011-2022 走看看