天天看點

(python)序列化自定義對象總結--改了類檔案的代碼之前的序列化自定義對象怎麼辦?

python中如果我改了自己之前的類代碼,那以前的序列化對象還能反序列化回來嗎?

着急的可以跳過代碼,直接看底下的結論.

class DemoClass:
    
    #初始版本
    def __init__(self,v1,v2,v3):
        self.v1=v1
        self.v2=v2
        self.v3=v3

    #初始版本
    def f1(self,vf11,vf12):
        print("我是即将要修改的部分")
        return vf11+vf12

    #初始版本,作為被删除的那個函數
    # def f2(self,vf21,vf22):
    #     return vf21-vf22

    #這個函數不能變,用來測試反序列化得到的對象能否正常使用
    def test1(self,testVarieble):
        print("受到的參數是,能看到這一行字說明測試函數一可以使用",testVarieble)

    '''1.1.增加新的方法,沒有使用到成員變量
    def newf(self):
        print('我是一個新的方法')'''

    """增加的新方法,要用到成員變量了
    def getv1(self):
        return  v1"""

    '''def bbbb(self):
        print("稀奇古怪")'''

    '''這裡看對原來的對象展示一下換名字的變量'''
    # def showv4(self):
    #     print(self.v4)
           

底下的是測試檔案:

import pickle
'''
下面說一下我最關心的問題,自定義對象的序列化和反序列化:
1.如果原來的類定義檔案發生了改變,還能不能反序列化,如果不能,怎樣才能?
            1.成員方法層面:
                1.增加新的方法,
                2.删除原來的方法,
                3.對原來的方法體做出修改
                4.對原來的方法的參數清單做出修改
            2.成員變量層面(其實這也算是對成員方法的修改):
                1.增加成員變量
                2.删除現有的成員變量
2.和import語句有沒有關系?是不是隻要導入正确的類就行?
'''
import 儲存問題.序列化與反序列化.DemoClass as dm
demo=dm.DemoClass("第一個成員變量v1","第一個成員變量v2","第一個成員變量v3")
result=pickle.dumps(demo)
print(result)
#原始序列化結果(什麼改動都沒有):        b'\x80\x04\x95\xa6\x00\x00\x00\x00\x00\x00\x00\x8c/\xe5\x82\xa8\xe5\xad\x98\xe9\x97\xae\xe9\xa2\x98.\xe5\xba\x8f\xe5\x88\x97\xe5\x8c\x96\xe4\xb8\x8e\xe5\x8f\x8d\xe5\xba\x8f\xe5\x88\x97\xe5\x8c\x96.DemoClass\x94\x8c\tDemoClass\x94\x93\x94)\x81\x94}\x94(\x8c\x02v1\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv1\x94\x8c\x02v2\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv2\x94\x8c\x02v3\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv3\x94ub.'
'''     
成員方法:
        增加一個成員方法後(該方法未使用成員變量):b'\x80\x04\x95\xa6\x00\x00\x00\x00\x00\x00\x00\x8c/\xe5\x82\xa8\xe5\xad\x98\xe9\x97\xae\xe9\xa2\x98.\xe5\xba\x8f\xe5\x88\x97\xe5\x8c\x96\xe4\xb8\x8e\xe5\x8f\x8d\xe5\xba\x8f\xe5\x88\x97\xe5\x8c\x96.DemoClass\x94\x8c\tDemoClass\x94\x93\x94)\x81\x94}\x94(\x8c\x02v1\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv1\x94\x8c\x02v2\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv2\x94\x8c\x02v3\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv3\x94ub.'
        結果:與原始對象序列化的結果相同,可以使用各項功能,包括新增的函數
        結論:沒有影響
        删除一個成員方法(該方法未使用成員變量),向一個函數中多加一句話,以及對使用到成員變量的成員變量進行以上操作
        結果:與上面那個相同
        結論:任意修改一個沒有使用成員變量的成員方法無影響
導包:
        把as後面那個dm改成dm1,沒有影響
        把檔案"序列化與反序列化"改為"序列化與反序列化1",反序列化不行了,找不到子產品了,再改回 原來的包名,就有可以了
構造函數:
        給原來的所有v3換成v4,理論上沒有真正的改變類,這時:
        1.可以反序列化,但是構造時相同的參數清單,序列化得到的結果卻不同
        2.當對原始資料調用使用v4的函數時會報錯,'DemoClass' object has no attribute 'v4'
        3.如果我把使用v4的函數注釋掉,當還是反序列并且得到化上一步的有該方法的對象,然後調用使用v4的方法,結果無疑報錯
'''
原始資料結果=b'\x80\x04\x95\xa6\x00\x00\x00\x00\x00\x00\x00\x8c/\xe5\x82\xa8\xe5\xad\x98\xe9\x97\xae\xe9\xa2\x98.\xe5\xba\x8f\xe5\x88\x97\xe5\x8c\x96\xe4\xb8\x8e\xe5\x8f\x8d\xe5\xba\x8f\xe5\x88\x97\xe5\x8c\x96.DemoClass\x94\x8c\tDemoClass\x94\x93\x94)\x81\x94}\x94(\x8c\x02v1\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv1\x94\x8c\x02v2\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv2\x94\x8c\x02v3\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv3\x94ub.'
#原始資料結果=b'\x80\x04\x95\xa6\x00\x00\x00\x00\x00\x00\x00\x8c/\xe5\x82\xa8\xe5\xad\x98\xe9\x97\xae\xe9\xa2\x98.\xe5\xba\x8f\xe5\x88\x97\xe5\x8c\x96\xe4\xb8\x8e\xe5\x8f\x8d\xe5\xba\x8f\xe5\x88\x97\xe5\x8c\x96.DemoClass\x94\x8c\tDemoClass\x94\x93\x94)\x81\x94}\x94(\x8c\x02v1\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv1\x94\x8c\x02v2\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv2\x94\x8c\x02v4\x94\x8c\x17\xe7\xac\xac\xe4\xb8\x80\xe4\xb8\xaa\xe6\x88\x90\xe5\x91\x98\xe5\x8f\x98\xe9\x87\x8fv3\x94ub.'


#判斷改變前後的同一對象序列化後的結果是否相同
print(result==原始資料結果)

#看最開始序列化後得到的結果用現在的類檔案還能不能反序列化
原始對象=pickle.loads(原始資料結果)

#測試此對象是否能使用
原始對象.test1("ss")
#原始對象.showv4()
transient
           

我猜想序列化隻要記錄這麼幾個資訊:

1.類的路徑(帶包名)

2.成員變量(變量名稱和變量的值)

并且反序列化的步驟如下:

1.按照儲存的類路徑找到這個對象的類

2.按照儲存的變量名稱和變量的值走構造方法建立一個該類的執行個體.

結論是:

隻要 1.類路徑的寫法不變,2.構造方法不變(形參可以變,但是成員變量的名稱不能變)

反序列化就一般沒有問題.

如果條件限制得更嚴格一點,

即如果隻改變了成員方法,構造時給的參數一樣,那麼甚至序列化的結果就是一摸一樣的.