1. 程式人生 > >python pickle模組學習理解(二)

python pickle模組學習理解(二)

上一篇記錄pickle基本操作,這一篇學習研究那些型別是可以pickle的。引用
Python’s pickle (I’m talking standard Python 2.5/2.6/2.7 here) cannot pickle locks, file objects etc.
It also cannot pickle generators and lambda expressions (or any other anonymous code), because the pickle really only stores name references.
Python的pickle(我在這裡說的標準Python 2.5 / 2.6 / 2.7)不能pickle lock、file物件等。
它也不能pickle生成器和lambda表示式(或任何其他匿名程式碼),因為pickle只儲存名稱引用。
pickle只儲存名稱引用怎麼理解。我寫了下面的測試程式碼。這裡我在同一目錄編寫兩個檔案,一個用來儲存,一個用來讀取。
測試1目標測試函式,普通函式和帶有生成器(yield語句)的函式
測試在一個檔案讀

# coding: utf8
import  pickle

import  pickle
def storeTree(filename,*args):
    with open(filename,'wb') as fw:  #開啟需要用'wb'
        for i in args:
            pickle.dump(i, fw,-1) #為了保護資料protocol=-1,設為0可以看到資料

def grabTree(filename):
    Mylist=[]   #返回變數的列表
    with open(filename,'rb') as fr:
        while True:        #這裡用try最簡單,不用定義迴圈次數
            try:
                Mylist.append(pickle.load(fr))
            except:
                break
    return Mylist

def  TextPick(s,j):
    return("{}:{}".format(s,j))

def Tyield(i=None):
    if i is None:
        i=2
    while 1:
        yield i
        i+=1
if __name__ == "__main__":
    filename = "pickT.txt"   #測試函式
    n = Tyield().__next__()
#    n=Tyield()    #執行這句出現錯誤
                   # can't pickle generator objects 執行這句不能pickle generator物件
    storeTree(filename,TextPick,n) #這裡n儲存的是一個整數
    s=grabTree(filename)
    print("返回第一個是函式結果={}".format(s[0](2,3)))
    print("返回第二個是函式型別={}".format(type(s[1])))
    print("返回第二個是函式結果={}".format(s[1]))

輸出:
返回第一個是函式結果=2:3
返回第二個是函式型別=<class ‘int’>
返回第二個是函式結果=2
第一個返回函式物件,第二個返回int物件執行完這個程式後我們看看其他程式呼叫

# coding: utf8
import  pickle

import  pickle
def grabTree(filename):
    Mylist=[]   #返回變數的列表
    with open(filename,'rb') as fr:
        while True:        #這裡用try最簡單,不用定義迴圈次數
            try:
                Mylist.append(pickle.load(fr))
            except:
                break
    return Mylist


def  TextPick(s,j):
    return ("{}:{}".format(s, j))


if __name__ == "__main__":
    filename = "pickT.txt"
    b1=grabTree(filename)[0]
    print("返回第調函式{}".format(b1))
    print("返回第調函式呼叫b1(2,3){}".format(b1(2,3)))

輸出:
返回第調函式<function TextPick at 0x01958078>
返回第調函式呼叫b1(2,3)2:3
這和我們的預期是一致的。不由考慮,如果讀取程式沒有定義TextPick怎摸樣 現在修改程式碼將TextPick改個名。執行

出現錯誤
File "D:/PYthonPro/CSV解析/量化序列化讀取.py", line 22, in <module>
    b1=grabTree(filename)[0]
IndexError: list index out of range

list index out of 應該是查詢沒有找到函式名越界了。
其次如果我們修改函式內容會怎麼樣
將TextPick改為看看執行結果

def  TextPick(s,j):
    return s+j

返回第調函式<function TextPick at 0x01938078>
返回第調函式呼叫b1(2,3)5
所以得出結論pickle儲存函式實際上儲存的函式名

討論完函式再討論一下類,呼叫類名和函式是相似的,兩個程式必須有相同的類名,因為類有內部變數,所以需要測試一下

# coding: utf8
import  pickle

import  pickle
def storeTree(filename,*args):
    with open(filename,'wb') as fw:  #開啟需要用'wb'
        for i in args:
            pickle.dump(i, fw,-1) #為了保護資料protocol=-1,設為0可以看到資料

def grabTree(filename):
    Mylist=[]   #返回變數的列表
    with open(filename,'rb') as fr:
        while True:        #這裡用try最簡單,不用定義迴圈次數
            try:
                Mylist.append(pickle.load(fr))
            except:
                break
    return Mylist

class Person:
    def __init__(self,n,a):
        self.name=n
        self.age=a
    def show(self):
        print("name={},age={}".format(self.name,self.age))
if __name__ == "__main__":
    filename = "pickT.txt"   #測試類和函式
    _P=Person
    aa = Person("JGood", 2)
    print("第一次例項")
    aa.show()
    storeTree(filename,aa,_P)

    s=grabTree(filename)
    b0=s[0]
    print("第二次例項")
    b0.show()
    b1 = s[1]
    b1例項=b1("趙虎",12)
    print("b1例項例項")
    b1例項.show()

輸出:
第一次例項
name=JGood,age=2
第二次例項
name=JGood,age=2
b1例項例項
name=趙虎,age=12
我們在另一個檔案讀取一下儲存的資料

# coding: utf8
import  pickle

import  pickle
def grabTree(filename):
    Mylist=[]   #返回變數的列表
    with open(filename,'rb') as fr:
        while True:        #這裡用try最簡單,不用定義迴圈次數
            try:
                Mylist.append(pickle.load(fr))
            except:
                break
    return Mylist


class Person:
    def __init__(self,n,a):
        self.name=n
        self.age=a
    def show(self):
        print("name={},age={}".format(self.name,self.age))

if __name__ == "__main__":
    filename = "pickT.txt"
    s = grabTree(filename)
    b0 = s[0]
    print("第二次例項")
    b0.show()
    b1 = s[1]
    b1例項 = b1("趙虎", 12)
    print("b1例項例項")
    b1例項.show()

輸出:
第二次例項
name=JGood,age=2 看到內部變數保留了
b1例項例項
name=趙虎,age=12

# coding: utf8
import  pickle

import  pickle
def grabTree(filename):
    Mylist=[]   #返回變數的列表
    with open(filename,'rb') as fr:
        while True:        #這裡用try最簡單,不用定義迴圈次數
            try:
                Mylist.append(pickle.load(fr))
            except:
                break
    return Mylist


class Person:
    def __init__(self,n,a):
        self.name=n
        self.age=a
        self.oth="name={},age={}".format(self.name,self.age) #增加一個變數
    def show(self):
        print("name={},age={}".format(self.name,self.age))



if __name__ == "__main__":
    filename = "pickT.txt"
    s = grabTree(filename)
    b0 = s[0]
    print("b0的內部變數{}".format(b0.__dict__))
    print("第二次例項")
    b0.show()
    b1 = s[1]
    b1例項 = b1("趙虎", 12)
    print(print("b1例項的內部變數{}".format(b1例項.__dict__)))
    print("b1例項例項")
    b1例項.show()

輸出:
b0的內部變數{‘name’: ‘JGood’, ‘age’: 2} 這裡有兩個變數
第二次例項
name=JGood,age=2
b1例項的內部變數{‘name’: ‘趙虎’, ‘age’: 12, ‘oth’: ‘name=趙虎,age=12’}

這裡有3個變數

None
b1例項例項
name=趙虎,age=12
從這裡可以看出 pickle只儲存名稱引用的含義