摘要:重構對象的問題當與你自己的類一起工作時,你必須保證類被腌漬出現在讀取的進程的命名空間中。因為使用值而不能被腌漬的類,可以定義和來返回狀態的一個子集,才能被腌漬。腌漬和反腌漬該圖來創建一個結點集合。
重構對象的問題承接上文 pickle和cPickle:Python對象的序列化(上) 。
當與你自己的類一起工作時,你必須保證類被腌漬出現在讀取pickle的進程的命名空間中。只有該實例的數據而不是類定義被腌漬。類名被用于在反腌漬時,找到構造器(constructor)以創建新對象。以此——往一個文件寫入一個類的實例為例:
pythontry: import cPickle as pickle except: import pickle import sys class SimpleObject(object): def __init__(self, name): self.name = name l = list(name) l.reverse() self.name_backwards = "".join(l) return if __name__ == "__main__": data = [] data.append(SimpleObject("pickle")) data.append(SimpleObject("cPickle")) data.append(SimpleObject("last")) try: filename = sys.argv[1] except IndexError: raise RuntimeError("Please specify a filename as an argument to %s" % sys.argv[0]) out_s = open(filename, "wb") try: # 寫入流中 for o in data: print "WRITING: %s (%s)" % (o.name, o.name_backwards) pickle.dump(o, out_s) finally: out_s.close()
在運行時,該腳本創建一個以在命令行指定的參數為名的文件:
python$ python pickle_dump_to_file_1.py test.dat WRITING: pickle (elkcip) WRITING: cPickle (elkciPc) WRITING: last (tsal)
一個在讀取結果腌漬對象失敗的簡化嘗試:
pythontry: import cPickle as pickle except: import pickle import pprint from StringIO import StringIO import sys try: filename = sys.argv[1] except IndexError: raise RuntimeError("Please specify a filename as an argument to %s" % sys.argv[0]) in_s = open(filename, "rb") try: # 讀取數據 while True: try: o = pickle.load(in_s) except EOFError: break else: print "READ: %s (%s)" % (o.name, o.name_backwards) finally: in_s.close()
該版本失敗的原因在于沒有 SimpleObject 類可用:
python$ python pickle_load_from_file_1.py test.dat Traceback (most recent call last): File "pickle_load_from_file_1.py", line 52, ino = pickle.load(in_s) AttributeError: "module" object has no attribute "SimpleObject"
正確的版本從原腳本中導入 SimpleObject ,可成功運行。
添加:
pythonfrom pickle_dump_to_file_1 import SimpleObject
至導入列表的尾部,接著重新運行該腳本:
python$ python pickle_load_from_file_2.py test.dat READ: pickle (elkcip) READ: cPickle (elkciPc) READ: last (tsal)
當腌漬有值的數據類型不能被腌漬時(套接字、文件句柄(file handles)、數據庫連接等之類的),有一些特別的考慮。因為使用值而不能被腌漬的類,可以定義 __getstate__() 和 __setstate__() 來返回狀態(state)的一個子集,才能被腌漬。新式類(New-style classes)也可以定義__getnewargs__(),該函數應當返回被傳遞至類內存分配器(the class memory allocator)(C.__new__())的參數。使用這些新特性的更多細節,包含在標準庫文檔中。
環形引用(Circular References)pickle協議(pickle protocol)自動處理對象間的環形引用,因此,即使是很復雜的對象,你也不用特別為此做什么。考慮下面這個圖:
上圖雖然包括幾個環形引用,但也能以正確的結構腌漬和重新讀?。╮eloaded)。
pythonimport pickle class Node(object): """ 一個所有結點都可知它所連通的其它結點的簡單有向圖。 """ def __init__(self, name): self.name = name self.connections = [] return def add_edge(self, node): "創建兩個結點之間的一條邊。" self.connections.append(node) return def __iter__(self): return iter(self.connections) def preorder_traversal(root, seen=None, parent=None): """產生器(Generator )函數通過一個先根遍歷(preorder traversal)生成(yield)邊。""" if seen is None: seen = set() yield (parent, root) if root in seen: return seen.add(root) for node in root: for (parent, subnode) in preorder_traversal(node, seen, root): yield (parent, subnode) return def show_edges(root): "打印圖中的所有邊。" for parent, child in preorder_traversal(root): if not parent: continue print "%5s -> %2s (%s)" % (parent.name, child.name, id(child)) # 創建結點。 root = Node("root") a = Node("a") b = Node("b") c = Node("c") # 添加邊。 root.add_edge(a) root.add_edge(b) a.add_edge(b) b.add_edge(a) b.add_edge(c) a.add_edge(a) print "ORIGINAL GRAPH:" show_edges(root) # 腌漬和反腌漬該圖來創建 # 一個結點集合。 dumped = pickle.dumps(root) reloaded = pickle.loads(dumped) print print "RELOADED GRAPH:" show_edges(reloaded)
重新讀取的諸多節點(譯者注:對應圖中的圓圈)不再是同一個對象,但是節點間的關系保持住了,而且讀取的僅僅是帶有多個引用的對象的一個拷貝。上面所說的可以通過測試各節點在pickle處理前和之后的id()值來驗證。
python$ python pickle_cycle.py ORIGINAL GRAPH: root -> a (4299721744) a -> b (4299721808) b -> a (4299721744) b -> c (4299721872) a -> a (4299721744) root -> b (4299721808) RELOADED GRAPH: root -> a (4299722000) a -> b (4299722064) b -> a (4299722000) b -> c (4299722128) a -> a (4299722000) root -> b (4299722064)
原文 pickle and cPickle – Python object serialization - Python Module of the Week 的后半部分。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/45345.html
摘要:對象序列化從這篇文章粗略翻譯的模塊可以實現任意的對象轉換為一系列字節即序列化對象的算法。的文檔明確的表明它不提供安全保證。而利用則可以控制序列化的細節。 Python 對象序列化——pickle and cPickle 從這篇文章粗略翻譯的pickle and cPickle pickle模塊可以實現任意的Python對象轉換為一系列字節(即序列化對象)的算法。這些字節流可以 被...
摘要:使用來創建一個表示該對象值的字符串。數據被序列化以后,你可以將它們寫入文件套接字管道等等中。如果你使用管道或者套接字,在通過連至另一端的連接傾倒所有對象推送數據之后,別忘了沖洗。 目的:Python對象序列化 可用性:pickle至少1.4版本,cPickle 1.5版本以上 pickle模塊實現了一種算法,將任意一個Python對象轉化成一系列字節(byets)。此過程也調用了s...
摘要:利用標準庫中的的模塊可以將對象轉換為一種可以傳輸或存儲的格式。主要方法模塊中有兩個主要函數,它們是和。具體語法為返回一個字符串,而不是存入文件中。該方法用于反序列化,即將序列化的對象重新恢復成對象。除此之外,這兩個模塊的接口是幾乎完全相同。 對象存在于程序運行時的內存中,當程序不再運行時或斷電關機時,這些對象便不再存在。我現在想把對象保存下來,方便以后使用,這就是持久化技術。利用 py...
摘要:默認為或者說,是以格式保存對象如果設置為或者,則以壓縮的二進制格式保存對象。但是,要小心坑試圖增加一個坑就在這里當試圖修改一個已有鍵的值時沒有報錯,但是并沒有修改成功。要填平這個坑,需要這樣做多一個參數沒有坑了還用循環一下 pickle pickle是標準庫中的一個模塊,在Python 2中還有一個cpickle,兩者的區別就是后者更快。所以,下面操作中,不管是用import pick...
摘要:反序列化安全問題一這一段時間使用做開發,使用了存儲,閱讀了源碼,發現在存儲到過程中,利用了模塊進行序列化以及反序列化正好根據該樣例學習一波反序列化相關的安全問題,不足之處請各位表哥指出。 Python 反序列化安全問題(一) 這一段時間使用flask做web開發,使用了redis存儲session,閱讀了flask_session源碼,發現在存儲session到redis過程中,利用了...
閱讀 4418·2021-11-19 09:59
閱讀 3335·2021-10-12 10:12
閱讀 2646·2021-09-22 15:25
閱讀 3349·2019-08-30 15:55
閱讀 1195·2019-08-29 11:27
閱讀 1473·2019-08-28 18:06
閱讀 2747·2019-08-26 13:41
閱讀 2564·2019-08-26 13:41