摘要:重構(gòu)對(duì)象的問(wèn)題當(dāng)與你自己的類(lèi)一起工作時(shí),你必須保證類(lèi)被腌漬出現(xiàn)在讀取的進(jìn)程的命名空間中。因?yàn)槭褂弥刀荒鼙浑鐫n的類(lèi),可以定義和來(lái)返回狀態(tài)的一個(gè)子集,才能被腌漬。腌漬和反腌漬該圖來(lái)創(chuàng)建一個(gè)結(jié)點(diǎn)集合。
重構(gòu)對(duì)象的問(wèn)題承接上文 pickle和cPickle:Python對(duì)象的序列化(上) 。
當(dāng)與你自己的類(lèi)一起工作時(shí),你必須保證類(lèi)被腌漬出現(xiàn)在讀取pickle的進(jìn)程的命名空間中。只有該實(shí)例的數(shù)據(jù)而不是類(lèi)定義被腌漬。類(lèi)名被用于在反腌漬時(shí),找到構(gòu)造器(constructor)以創(chuàng)建新對(duì)象。以此——往一個(gè)文件寫(xiě)入一個(gè)類(lèi)的實(shí)例為例:
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: # 寫(xiě)入流中 for o in data: print "WRITING: %s (%s)" % (o.name, o.name_backwards) pickle.dump(o, out_s) finally: out_s.close()
在運(yùn)行時(shí),該腳本創(chuàng)建一個(gè)以在命令行指定的參數(shù)為名的文件:
python$ python pickle_dump_to_file_1.py test.dat WRITING: pickle (elkcip) WRITING: cPickle (elkciPc) WRITING: last (tsal)
一個(gè)在讀取結(jié)果腌漬對(duì)象失敗的簡(jiǎn)化嘗試:
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: # 讀取數(shù)據(jù) 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()
該版本失敗的原因在于沒(méi)有 SimpleObject 類(lèi)可用:
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"
正確的版本從原腳本中導(dǎo)入 SimpleObject ,可成功運(yùn)行。
添加:
pythonfrom pickle_dump_to_file_1 import SimpleObject
至導(dǎo)入列表的尾部,接著重新運(yùn)行該腳本:
python$ python pickle_load_from_file_2.py test.dat READ: pickle (elkcip) READ: cPickle (elkciPc) READ: last (tsal)
當(dāng)腌漬有值的數(shù)據(jù)類(lèi)型不能被腌漬時(shí)(套接字、文件句柄(file handles)、數(shù)據(jù)庫(kù)連接等之類(lèi)的),有一些特別的考慮。因?yàn)槭褂弥刀荒鼙浑鐫n的類(lèi),可以定義 __getstate__() 和 __setstate__() 來(lái)返回狀態(tài)(state)的一個(gè)子集,才能被腌漬。新式類(lèi)(New-style classes)也可以定義__getnewargs__(),該函數(shù)應(yīng)當(dāng)返回被傳遞至類(lèi)內(nèi)存分配器(the class memory allocator)(C.__new__())的參數(shù)。使用這些新特性的更多細(xì)節(jié),包含在標(biāo)準(zhǔn)庫(kù)文檔中。
環(huán)形引用(Circular References)pickle協(xié)議(pickle protocol)自動(dòng)處理對(duì)象間的環(huán)形引用,因此,即使是很復(fù)雜的對(duì)象,你也不用特別為此做什么??紤]下面這個(gè)圖:
上圖雖然包括幾個(gè)環(huán)形引用,但也能以正確的結(jié)構(gòu)腌漬和重新讀?。╮eloaded)。
pythonimport pickle class Node(object): """ 一個(gè)所有結(jié)點(diǎn)都可知它所連通的其它結(jié)點(diǎn)的簡(jiǎn)單有向圖。 """ def __init__(self, name): self.name = name self.connections = [] return def add_edge(self, node): "創(chuàng)建兩個(gè)結(jié)點(diǎn)之間的一條邊。" self.connections.append(node) return def __iter__(self): return iter(self.connections) def preorder_traversal(root, seen=None, parent=None): """產(chǎn)生器(Generator )函數(shù)通過(guò)一個(gè)先根遍歷(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)) # 創(chuàng)建結(jié)點(diǎn)。 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) # 腌漬和反腌漬該圖來(lái)創(chuàng)建 # 一個(gè)結(jié)點(diǎn)集合。 dumped = pickle.dumps(root) reloaded = pickle.loads(dumped) print print "RELOADED GRAPH:" show_edges(reloaded)
重新讀取的諸多節(jié)點(diǎn)(譯者注:對(duì)應(yīng)圖中的圓圈)不再是同一個(gè)對(duì)象,但是節(jié)點(diǎn)間的關(guān)系保持住了,而且讀取的僅僅是帶有多個(gè)引用的對(duì)象的一個(gè)拷貝。上面所說(shuō)的可以通過(guò)測(cè)試各節(jié)點(diǎn)在pickle處理前和之后的id()值來(lái)驗(yàn)證。
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 的后半部分。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/45345.html
摘要:對(duì)象序列化從這篇文章粗略翻譯的模塊可以實(shí)現(xiàn)任意的對(duì)象轉(zhuǎn)換為一系列字節(jié)即序列化對(duì)象的算法。的文檔明確的表明它不提供安全保證。而利用則可以控制序列化的細(xì)節(jié)。 Python 對(duì)象序列化——pickle and cPickle 從這篇文章粗略翻譯的pickle and cPickle pickle模塊可以實(shí)現(xiàn)任意的Python對(duì)象轉(zhuǎn)換為一系列字節(jié)(即序列化對(duì)象)的算法。這些字節(jié)流可以 被...
摘要:使用來(lái)創(chuàng)建一個(gè)表示該對(duì)象值的字符串。數(shù)據(jù)被序列化以后,你可以將它們寫(xiě)入文件套接字管道等等中。如果你使用管道或者套接字,在通過(guò)連至另一端的連接傾倒所有對(duì)象推送數(shù)據(jù)之后,別忘了沖洗。 目的:Python對(duì)象序列化 可用性:pickle至少1.4版本,cPickle 1.5版本以上 pickle模塊實(shí)現(xiàn)了一種算法,將任意一個(gè)Python對(duì)象轉(zhuǎn)化成一系列字節(jié)(byets)。此過(guò)程也調(diào)用了s...
摘要:利用標(biāo)準(zhǔn)庫(kù)中的的模塊可以將對(duì)象轉(zhuǎn)換為一種可以傳輸或存儲(chǔ)的格式。主要方法模塊中有兩個(gè)主要函數(shù),它們是和。具體語(yǔ)法為返回一個(gè)字符串,而不是存入文件中。該方法用于反序列化,即將序列化的對(duì)象重新恢復(fù)成對(duì)象。除此之外,這兩個(gè)模塊的接口是幾乎完全相同。 對(duì)象存在于程序運(yùn)行時(shí)的內(nèi)存中,當(dāng)程序不再運(yùn)行時(shí)或斷電關(guān)機(jī)時(shí),這些對(duì)象便不再存在。我現(xiàn)在想把對(duì)象保存下來(lái),方便以后使用,這就是持久化技術(shù)。利用 py...
摘要:默認(rèn)為或者說(shuō),是以格式保存對(duì)象如果設(shè)置為或者,則以壓縮的二進(jìn)制格式保存對(duì)象。但是,要小心坑試圖增加一個(gè)坑就在這里當(dāng)試圖修改一個(gè)已有鍵的值時(shí)沒(méi)有報(bào)錯(cuò),但是并沒(méi)有修改成功。要填平這個(gè)坑,需要這樣做多一個(gè)參數(shù)沒(méi)有坑了還用循環(huán)一下 pickle pickle是標(biāo)準(zhǔn)庫(kù)中的一個(gè)模塊,在Python 2中還有一個(gè)cpickle,兩者的區(qū)別就是后者更快。所以,下面操作中,不管是用import pick...
摘要:反序列化安全問(wèn)題一這一段時(shí)間使用做開(kāi)發(fā),使用了存儲(chǔ),閱讀了源碼,發(fā)現(xiàn)在存儲(chǔ)到過(guò)程中,利用了模塊進(jìn)行序列化以及反序列化正好根據(jù)該樣例學(xué)習(xí)一波反序列化相關(guān)的安全問(wèn)題,不足之處請(qǐng)各位表哥指出。 Python 反序列化安全問(wèn)題(一) 這一段時(shí)間使用flask做web開(kāi)發(fā),使用了redis存儲(chǔ)session,閱讀了flask_session源碼,發(fā)現(xiàn)在存儲(chǔ)session到redis過(guò)程中,利用了...
閱讀 4750·2021-11-19 09:59
閱讀 3629·2021-10-12 10:12
閱讀 2802·2021-09-22 15:25
閱讀 3491·2019-08-30 15:55
閱讀 1347·2019-08-29 11:27
閱讀 1631·2019-08-28 18:06
閱讀 2905·2019-08-26 13:41
閱讀 2716·2019-08-26 13:41