持久性就是指保持對象,甚至在多次執(zhí)行同一程序之間也保持對象。通過本文,您會對Python對象的各種持久性機(jī)制(從關(guān)系數(shù)據(jù)庫到Python的pickle以及其它機(jī)制)有一個總體認(rèn)識。另外,還會讓您更深一步地了解Python的對象序列化能力。
什么是持久性?
持久性的基本思想很簡單。假定有一個Python程序,它可能是一個管理日常待辦事項(xiàng)的程序,您希望在多次執(zhí)行這個程序之間可以保存應(yīng)用程序?qū)ο?待辦事項(xiàng))。換句話說,您希望將對象存儲在磁盤上,便于以后檢索。這就是持久性。要達(dá)到這個目的,有幾種方法,每一種方法都有其優(yōu)缺點(diǎn)。
例如,可以將對象數(shù)據(jù)存儲在某種格式的文本文件中,譬如CSV文件?;蛘呖梢杂藐P(guān)系數(shù)據(jù)庫,譬如Gadfly、MySQL、PostgreSQL或者DB2。這些文件格式和數(shù)據(jù)庫都非常優(yōu)秀,對于所有這些存儲機(jī)制,Python都有健壯的接口。
這些存儲機(jī)制都有一個共同點(diǎn):存儲的數(shù)據(jù)是獨(dú)立于對這些數(shù)據(jù)進(jìn)行操作的對象和程序。這樣做的好處是,數(shù)據(jù)可以作為共享的資源,供其它應(yīng)用程序使用。缺點(diǎn)是,用這種方式,可以允許其它程序訪問對象的數(shù)據(jù),這違背了面向?qū)ο蟮姆庋b性原則—即對象的數(shù)據(jù)只能通過這個對象自身的公共(public)接口來訪問。
另外,對于某些應(yīng)用程序,關(guān)系數(shù)據(jù)庫方法可能不是很理想。尤其是,關(guān)系數(shù)據(jù)庫不理解對象。相反,關(guān)系數(shù)據(jù)庫會強(qiáng)行使用自己的類型系統(tǒng)和關(guān)系數(shù)據(jù)模型(表),每張表包含一組元組(行),每行包含具有固定數(shù)目的靜態(tài)類型字段(列)。如果應(yīng)用程序的對象模型不能夠方便地轉(zhuǎn)換到關(guān)系模型,那么在將對象映射到元組以及將元組映射回對象方面,會碰到一定難度。這種困難常被稱為阻礙性不匹配(impedence-mismatch)問題。
對象持久性
如果希望透明地存儲Python對象,而不丟失其身份和類型等信息,則需要某種形式的對象序列化:它是一個將任意復(fù)雜的對象轉(zhuǎn)成對象的文本或二進(jìn)制表示的過程。同樣,必須能夠?qū)ο蠼?jīng)過序列化后的形式恢復(fù)到原有的對象。在Python中,這種序列化過程稱為pickle,可以將對象pickle成字符串、磁盤上的文件或者任何類似于文件的對象,也可以將這些字符串、文件或任何類似于文件的對象unpickle成原來的對象。我們將在本文后面詳細(xì)討論pickle。
假定您喜歡將任何事物都保存成對象,而且希望避免將對象轉(zhuǎn)換成某種基于非對象存儲的開銷;那么pickle文件可以提供這些好處,但有時可能需要比這種簡單的pickle文件更健壯以及更具有可伸縮性的事物。例如,只用pickle不能解決命名和查找pickle文件這樣的問題,另外,它也不能支持并發(fā)地訪問持久性對象。如果需要這些方面的功能,則要求助類似于ZODB(針對Python的Z對象數(shù)據(jù)庫)這類數(shù)據(jù)庫。ZODB是一個健壯的、多用戶的和面向?qū)ο蟮臄?shù)據(jù)庫系統(tǒng),它能夠存儲和管理任意復(fù)雜的Python對象,并支持事務(wù)操作和并發(fā)控制。(請參閱參考資料,以下載ZODB。)令人足夠感興趣的是,甚至ZODB也依靠Python的本機(jī)序列化能力,而且要有效地使用ZODB,必須充分了解pickle。
另一種令人感興趣的解決持久性問題的方法是Prevayler,它最初是用Java實(shí)現(xiàn)的(有關(guān)Prevaylor方面的developerWorks文章,請參閱參考資料)。最近,一群Python程序員將Prevayler移植到了Python上,另起名為PyPerSyst,由SourceForge托管(有關(guān)至PyPerSyst項(xiàng)目的鏈接,請參閱參考資料)。Prevayler/PyPerSyst概念也是建立在Java和Python語言的本機(jī)序列化能力之上。PyPerSyst將整個對象系統(tǒng)保存在內(nèi)存中,并通過不時地將系統(tǒng)快照pickle到磁盤以及維護(hù)一個命令日志(通過此日志可以重新應(yīng)用最新的快照)來提供災(zāi)難恢復(fù)。所以,盡管使用PyPerSyst的應(yīng)用程序受到可用內(nèi)存的限制,但好處是本機(jī)對象系統(tǒng)可以完全裝入到內(nèi)存中,因而速度極快,而且實(shí)現(xiàn)起來要比如ZODB這樣的數(shù)據(jù)庫簡單,ZODB允許對象的數(shù)目比同時在能內(nèi)存中所保持的對象要多。
既然我們已經(jīng)簡要討論了存儲持久對象的各種方法,那么現(xiàn)在該詳細(xì)探討pickle過程了。雖然我們主要感興趣的是探索以各種方式來保存Python對象,而不必將其轉(zhuǎn)換成某種其它格式,但我們?nèi)匀贿€有一些需要關(guān)注的地方,譬如:如何有效地pickle和unpickle簡單對象以及復(fù)雜對象,包括定制類的實(shí)例;如何維護(hù)對象的引用,包括循環(huán)引用和遞歸引用;以及如何處理類定義發(fā)生的變化,從而使用以前經(jīng)過pickle的實(shí)例時不會發(fā)生問題。我們將在隨后關(guān)于Python的pickle能力探討中涉及所有這些問題。
一些經(jīng)過pickle的Python
pickle模塊及其同類模塊cPickle向Python提供了pickle支持。后者是用C編碼的,它具有更好的性能,對于大多數(shù)應(yīng)用程序,推薦使用該模塊。我們將繼續(xù)討論pickle,但本文的示例實(shí)際是利用了cPickle。由于其中大多數(shù)示例要用Pythonshell來顯示,所以先展示一下如何導(dǎo)入cPickle,并可以作為pickle來引用它:
>>>importcPickleaspickle
現(xiàn)在已經(jīng)導(dǎo)入了該模塊,接下來讓我們看一下pickle接口。pickle模塊提供了以下函數(shù)對:dumps(object)返回一個字符串,它包含一個pickle格式的對象;loads(string)返回包含在pickle字符串中的對象;dump(object,file)將對象寫到文件,這個文件可以是實(shí)際的物理文件,但也可以是任何類似于文件的對象,這個對象具有write()方法,可以接受單個的字符串參數(shù);load(file)返回包含在pickle文件中的對象。
缺省情況下,dumps()和dump()使用可打印的ASCII表示來創(chuàng)建pickle。兩者都有一個final參數(shù)(可選),如果為True,則該參數(shù)指定用更快以及更小的二進(jìn)制表示來創(chuàng)建pickle。loads()和load()函數(shù)自動檢測pickle是二進(jìn)制格式還是文本格式。
以上內(nèi)容為大家介紹了pythonpickle模塊,希望對大家有所幫助,如果想要了解更多Python相關(guān)知識,請關(guān)注IT培訓(xùn)機(jī)構(gòu):千鋒教育。