摘要:對(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é)流可以 被傳輸或存儲(chǔ),接著也可以重構(gòu)為一個(gè)和原先對(duì)象具有相同特征的新對(duì)象。
cPickle模塊實(shí)現(xiàn)了同樣的算法,但它是用c而不是python。因此,它比python實(shí)現(xiàn)的快上好幾倍, 但是不允許使用者去繼承Pickle。如果繼承對(duì)于你的使用不是很重要,那么你大可以使用cPickle。
Woring: pickle的文檔明確的表明它不提供安全保證。所以慎用pickle來(lái)作為內(nèi)部進(jìn)程通信或者數(shù)
據(jù)存儲(chǔ),也不要相信那些你不能驗(yàn)證安全性的數(shù)據(jù)。
通常優(yōu)先試用 cPickle,只有當(dāng) cPickle 無(wú)法正常 import 的時(shí)候,采用 pickle 來(lái)替代。
try: import cPickle as pickle except: import pickleEncoding and Decoding Data in Strings
第一個(gè)示例是將數(shù)據(jù)結(jié)構(gòu)編碼為字符串,然后輸出到控制臺(tái)。例子中數(shù)據(jù)結(jié)構(gòu)完全由基本類型組成。pickle 可以編碼任意類的實(shí)例,就像下面栗子中演示的那樣:用 pickle.dumps() 來(lái)創(chuàng)建對(duì)象的字符串表示。
try: import cPickle as pickle except: import pickle import pprint data = [ { "a":"A", "b":2, "c":3.0 } ] print "DATA:", pprint.pprint(data) data_string = pickle.dumps(data) print "PICKLE:", data_string
pickle 默認(rèn)試用 ASSCII 字符串來(lái)進(jìn)行編碼解碼。也支持效率更高的二進(jìn)制格式,但是下面的例子為了方便閱讀,還是使用了 ASSCII 碼。
$ python pickle_string.py DATA:[{"a": "A", "b": 2, "c": 3.0}] PICKLE: (lp1 (dp2 S"a" S"A" sS"c" F3 sS"b" I2 sa.
數(shù)據(jù)被序列化之后,你就可以將他寫入文件、socket、pipe、etc.然后你可以讀取文件并unpickle 這些數(shù)據(jù)來(lái)構(gòu)造一個(gè)新的對(duì)象。
try: import cPickle as pickle except: import pickle import pprint data1 = [ { "a":"A", "b":2, "c":3.0 } ] print "BEFORE:", pprint.pprint(data1) data1_string = pickle.dumps(data1) data2 = pickle.loads(data1_string) print "AFTER:", pprint.pprint(data2) print "SAME?:", (data1 is data2) print "EQUAL?:", (data1 == data2)
如同例子中演示的那樣,新的對(duì)象與之前的對(duì)象相等,但是并不是同一個(gè)對(duì)象。
Working with Streams
$ python pickle_unpickle.py BEFORE:[{"a": "A", "b": 2, "c": 3.0}] AFTER:[{"a": "A", "b": 2, "c": 3.0}] SAME?: False EQUAL?: True
除了 dumps() 跟 loads(), pickle 還有其他比較方便的方法來(lái)操作類文件流??梢酝瑫r(shí)寫入多個(gè)對(duì)象到一個(gè) stream 中,然后對(duì)象數(shù)量與大小的時(shí)候從 stream 讀取他們。
try: import cPickle as pickle except: import pickle import pprint from StringIO import StringIO class SimpleObject(object): def __init__(self, name): self.name = name l = list(name) l.reverse() self.name_backwards = "".join(l) return data = [] data.append(SimpleObject("pickle")) data.append(SimpleObject("cPickle")) data.append(SimpleObject("last")) # Simulate a file with StringIO out_s = StringIO() # Write to the stream for o in data: print "WRITING: %s (%s)" % (o.name, o.name_backwards) pickle.dump(o, out_s) out_s.flush() # Set up a read-able stream in_s = StringIO(out_s.getvalue()) # Read the data while True: try: o = pickle.load(in_s) except EOFError: break else: print "READ: %s (%s)" % (o.name, o.name_backwards)
上面例子中使用了 StringIO 緩沖區(qū)來(lái)模擬streams,這樣我們?cè)诮⒖勺x流的時(shí)候可以玩一些技巧。一些接單的數(shù)據(jù)庫(kù)格式也可以使用 pickles 來(lái)存儲(chǔ)數(shù)據(jù),當(dāng)然,如果試用 shelve 來(lái)存儲(chǔ)會(huì)更加簡(jiǎn)單。
$ python pickle_stream.py WRITING: pickle (elkcip) WRITING: cPickle (elkciPc) WRITING: last (tsal) READ: pickle (elkcip) READ: cPickle (elkciPc) READ: last (tsal)
除了存儲(chǔ)數(shù)據(jù),pickles 用來(lái)做內(nèi)部通信的機(jī)會(huì)也很多。舉個(gè)例子:用 os.fork() 和 os.pipe() 可以建立一個(gè)工作進(jìn)程,然后這個(gè)進(jìn)程會(huì)從管道中讀取數(shù)據(jù)并把結(jié)果傳遞給另外一個(gè)管道。因?yàn)檫@些代碼是用來(lái)管理worker pool 跟 發(fā)送任務(wù)跟接受任務(wù)的,沒(méi)有什么特殊的內(nèi)容,所以這些核心代碼可以被拿來(lái)重復(fù)利用。如果你在試用 pipe 或者 sockets,那么在 dumping完對(duì)象之后,不要忘記刷新它們并通過(guò)其間的連接將數(shù)據(jù)推送到另外一個(gè)進(jìn)程。如果你不想自己寫 worker pool manager 的話,可以看一下multiprocessing。
Problems Reconstructing Objects需要注意的是,在序列化實(shí)例的時(shí)候,我們只是對(duì)于數(shù)據(jù)來(lái)進(jìn)行序列化,而無(wú)法對(duì)類的定義進(jìn)行序列化。
下面的栗子:
try: 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: # Write to the stream 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í)候,這個(gè)腳本會(huì)以命令行中給出的參數(shù)創(chuàng)建一個(gè)文件。
$ python pickle_dump_to_file_1.py test.dat WRITING: pickle (elkcip) WRITING: cPickle (elkciPc) WRITING: last (tsal)
下面是一個(gè)會(huì)報(bào)錯(cuò)的栗子:
try: 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: # Read the data 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()
這個(gè)報(bào)錯(cuò)是因?yàn)闆](méi)有SimpleObject類。
$ 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"
我們通過(guò)從原來(lái)的腳本中import SimpleObject來(lái)修正上面的錯(cuò)誤。
在上面文件中的增加下面一行:
from pickle_dump_to_file_1 import SimpleObject
$ python pickle_load_from_file_2.py test.dat READ: pickle (elkcip) READ: cPickle (elkciPc) READ: last (tsal)
像sockets, file handles, database connections ...這些數(shù)據(jù)類型是無(wú)法被序列化的,我們?cè)谔幚眍愃茢?shù)據(jù)類型的時(shí)候不得不特殊處理。而利用pickle protocol 則可以控制序列化的細(xì)節(jié)。
class Data(object): def __init__(self, x, y): self._x = x self._y = y def __getstate__(self): d = self.__dict__.copy() del d["_y"] return d def __setstate__(self, state): self.__dict__.update(state) d = Data(10, 20) s = cPickle.dumps(d, 2) d2 = cPickle.loads(s) ##d2.__dict__ ##{"_x": 10}
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/37359.html
摘要:使用來(lái)創(chuàng)建一個(gè)表示該對(duì)象值的字符串。數(shù)據(jù)被序列化以后,你可以將它們寫入文件套接字管道等等中。如果你使用管道或者套接字,在通過(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...
摘要:重構(gòu)對(duì)象的問(wèn)題當(dāng)與你自己的類一起工作時(shí),你必須保證類被腌漬出現(xiàn)在讀取的進(jìn)程的命名空間中。因?yàn)槭褂弥刀荒鼙浑鐫n的類,可以定義和來(lái)返回狀態(tài)的一個(gè)子集,才能被腌漬。腌漬和反腌漬該圖來(lái)創(chuàng)建一個(gè)結(jié)點(diǎn)集合。 承接上文 pickle和cPickle:Python對(duì)象的序列化(上) 。 重構(gòu)對(duì)象的問(wèn)題 當(dāng)與你自己的類一起工作時(shí),你必須保證類被腌漬出現(xiàn)在讀取pickle的進(jìn)程的命名空間中。...
摘要:反序列化安全問(wèn)題一這一段時(shí)間使用做開發(fā),使用了存儲(chǔ),閱讀了源碼,發(fā)現(xiàn)在存儲(chǔ)到過(guò)程中,利用了模塊進(jìn)行序列化以及反序列化正好根據(jù)該樣例學(xué)習(xí)一波反序列化相關(guān)的安全問(wèn)題,不足之處請(qǐng)各位表哥指出。 Python 反序列化安全問(wèn)題(一) 這一段時(shí)間使用flask做web開發(fā),使用了redis存儲(chǔ)session,閱讀了flask_session源碼,發(fā)現(xiàn)在存儲(chǔ)session到redis過(guò)程中,利用了...
摘要:利用標(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...
閱讀 3999·2021-09-09 09:33
閱讀 1908·2021-09-06 15:14
閱讀 1987·2019-08-30 15:44
閱讀 3164·2019-08-29 18:36
閱讀 3829·2019-08-29 16:22
閱讀 2151·2019-08-29 16:21
閱讀 2624·2019-08-29 15:42
閱讀 1707·2019-08-29 11:00