歡迎您光臨本站 註冊首頁

LINUX應用技巧,序列化存儲Python對象

←手機掃碼閱讀     火星人 @ 2014-03-26 , reply:0

  什麼是持久性?
  持久性的基本思想很簡單。假定有一個 Python 程序,它可能是一個管理日常待辦事項的程序,您希望在多次執行這個程序之間可以保存應用程序對象(待辦事項)。換句話說,您希望將對象存儲在磁碟上,便於以後檢索。這就是持久性。要達到這個目的,有幾種方法,每一種方法都有其優缺點。
  
  例如,可以將對象數據存儲在某種格式的文本文件中,譬如 CSV 文件。或者可以用關係資料庫,譬如 Gadfly、MySQL、PostgreSQL 或者 DB2。這些文件格式和資料庫都非常優秀,對於所有這些存儲機制,Python 都有健壯的介面。
  
  這些存儲機制都有一個共同點:存儲的數據是獨立於對這些數據進行操作的對象和程序。這樣做的好處是,數據可以作為共享的資源,供其它應用程序使用。缺點是,用這種方式,可以允許其它程序訪問對象的數據,這違背了面向對象的封裝性原則 — 即對象的數據只能通過這個對象自身的公共(public)介面來訪問。
  
  另外,對於某些應用程序,關係資料庫方法可能不是很理想。尤其是,關係資料庫不理解對象。相反,關係資料庫會強行使用自己的類型系統和關係數據模型(表),每張表包含一組元組(行),每行包含具有固定數目的靜態類型欄位(列)。如果應用程序的對象模型不能夠方便地轉換到關係模型,那麼在將對象映射到元組以及將元組映射回對象方面,會碰到一定難度。這種困難常被稱為阻礙性不匹配(impedence-mismatch)問題。
  
  對象持久性
  如果希望透明地存儲 Python 對象,而不丟失其身份和類型等信息,則需要某種形式的對象序列化:它是一個將任意複雜的對象轉成對象的文本或二進位表示的過程。同樣,必須能夠將對象經過序列化后的形式恢復到原有的對象。在 Python 中,這種序列化過程稱為 pickle,可以將對象 pickle 成字元串、磁碟上的文件或者任何類似於文件的對象,也可以將這些字元串、文件或任何類似於文件的對象 unpickle 成原來的對象。我們將在本文後面詳細討論 pickle。
  
  假定您喜歡將任何事物都保存成對象,而且希望避免將對象轉換成某種基於非對象存儲的開銷;那麼 pickle 文件可以提供這些好處,但有時可能需要比這種簡單的 pickle 文件更健壯以及更具有可伸縮性的事物。例如,只用 pickle 不能解決命名和查找 pickle 文件這樣的問題,另外,它也不能支持併發地訪問持久性對象。如果需要這些方面的功能,則要求助類似於 ZODB(針對 Python 的 Z 對象資料庫)這類資料庫。ZODB 是一個健壯的、多用戶的和面向對象的資料庫系統,它能夠存儲和管理任意複雜的 Python 對象,並支持事務操作和併發控制。(請參閱參考資料,以下載 ZODB。)令人足夠感興趣的是,甚至 ZODB 也依靠 Python 的本機序列化能力,而且要有效地使用 ZODB,必須充分了解 pickle。
  
  另一種令人感興趣的解決持久性問題的方法是 Prevayler,它最初是用 Java 實現的(有關 Prevaylor 方面的 developerWorks 文章,請參閱參考資料)。最近,一群 Python 程序員將 Prevayler 移植到了 Python 上,另起名為 PyPerSyst,由 SourceForge 託管(有關至 PyPerSyst 項目的鏈接,請參閱參考資料)。Prevayler/PyPerSyst 概念也是建立在 Java 和 Python 語言的本機序列化能力之上。PyPerSyst 將整個對象系統保存在內存中,並通過不時地將系統快照 pickle 到磁碟以及維護一個命令日誌(通過此日誌可以重新應用最新的快照)來提供災難恢復。所以,儘管使用 PyPerSyst 的應用程序受到可用內存的限制,但好處是本機對象系統可以完全裝入到內存中,因而速度極快,而且實現起來要比如 ZODB 這樣的資料庫簡單,ZODB 允許對象的數目比同時在能內存中所保持的對象要多。
  
  既然我們已經簡要討論了存儲持久對象的各種方法,那麼現在該詳細探討 pickle 過程了。雖然我們主要感興趣的是探索以各種方式來保存 Python 對象,而不必將其轉換成某種其它格式,但我們仍然還有一些需要關注的地方,譬如:如何有效地 pickle 和 unpickle 簡單對象以及複雜對象,包括定製類的實例;如何維護對象的引用,包括循環引用和遞歸引用;以及如何處理類定義發生的變化,從而使用以前經過 pickle 的實例時不會發生問題。我們將在隨後關於 Python 的 pickle 能力探討中涉及所有這些問題。
  
  一些經過 pickle 的 Python
  pickle 模塊及其同類模塊 cPickle 向 Python 提供了 pickle 支持。後者是用 C 編碼的,它具有更好的性能,對於大多數應用程序,推薦使用該模塊。我們將繼續討論 pickle,但本文的示例實際是利用了 cPickle。由於其中大多數示例要用 Python shell 來顯示,所以先展示一下如何導入 cPickle,並可以作為 pickle 來引用它:
  
  >>> import cPickle as pickle
  現在已經導入了該模塊,接下來讓我們看一下 pickle 介面。pickle 模塊提供了以下函數對:dumps(object) 返回一個字元串,它包含一個 pickle 格式的對象;loads(string) 返回包含在 pickle 字元串中的對象;dump(object, file) 將對象寫到文件,這個文件可以是實際的物理文件,但也可以是任何類似於文件的對象,這個對象具有 write() 方法,可以接受單個的字元串參數;load(file) 返回包含在 pickle 文件中的對象。
  
  預設情況下,dumps() 和 dump() 使用可列印的 ASCII 表示來創建 pickle。兩者都有一個 final 參數(可選),如果為 True,則該參數指定用更快以及更小的二進位表示來創建 pickle。loads() 和 load() 函數自動檢測 pickle 是二進位格式還是文本格式。
  
  清單 1 顯示了一個互動式會話,這裡使用了剛才所描述的 dumps() 和 loads() 函數:
  
  清單 1. dumps() 和 loads() 的演示
  Welcome To PyCrust 0.7.2 - The Flakiest Python Shell
  Sponsored by Orbtech - Your source for Python programming expertise.
  Python 2.2.1 (#1, Aug 27 2002, 10:22:32)
  [GCC 3.2 (Mandrake Linux 9.0 3.2-1mdk)] on linux-i386
  Type "copyright", "credits" or "license" for more information.
  >>> import cPickle as pickle
  >>> t1 = ('this is a string', 42, [1, 2, 3], None)
  >>> t1
  ('this is a string', 42, [1, 2, 3], None)
  >>> p1 = pickle.dumps(t1)
  >>> p1
  "(S'this is a string'\nI42\n(lp1\nI1\naI2\naI3\naNtp2\n."
  >>> print p1
  (S'this is a string'
  I42
  (lp1
  I1
  aI2
  aI3
  aNtp2
  .
  >>> t2 = pickle.loads(p1)
  >>> t2
  ('this is a string', 42, [1, 2, 3], None)
  >>> p2 = pickle.dumps(t1, True)
  >>> p2
  '(U\x10this is a stringK*]q\x01(K\x01K\x02K\x03eNtq\x02.'
  >>> t3 = pickle.loads(p2)
  >>> t3
  ('this is a string', 42, [1, 2, 3], None)
  
  註:該文本 pickle 格式很簡單,這裡就不解釋了。事實上,在 pickle 模塊中記錄了所有使用的約定。我們還應該指出,在我們的示例中使用的都是簡單對象,因此使用二進位 pickle 格式不會在節省空間上顯示出太大的效率。然而,在實際使用複雜對象的系統中,您會看到,使用二進位格式可以在大小和速度方面帶來顯著的改進。
  
  接下來,我們看一些示例,這些示例用到了 dump() 和 load(),它們使用文件和類似文件的對象。這些函數的操作非常類似於我們剛才所看到的 dumps() 和 loads(),區別在於它們還有另一種能力 — dump() 函數能一個接著一個地將幾個對象轉儲到同一個文件。隨後調用 load() 來以同樣的順序檢索這些對象。清單 2 顯示了這種能力的實際應用:
  
  清單 2. dump() 和 load() 示例
  >>> a1 = 'apple'
  >>> b1 = {1: 'One', 2: 'Two', 3: 'Three'}
  >>> c1 = ['fee', 'fie', 'foe', 'fum']
  >>> f1 = file('temp.pkl', 'wb')
  >>> pickle.dump(a1, f1, True)
  >>> pickle.dump(b1, f1, True)
  >>> pickle.dump(c1, f1, True)
  >>> f1.close()
  >>> f2 = file('temp.pkl', 'rb')
  >>> a2 = pickle.load(f2)
  >>> a2
  'apple'
  >>> b2 = pickle.load(f2)
  >>> b2
  {1: 'One', 2: 'Two', 3: 'Three'}
  >>> c2 = pickle.load(f2)
  >>> c2
  ['fee', 'fie', 'foe', 'fum']
  >>> f2.close()
  
  Pickle 的威力
  到目前為止,我們講述了關於 pickle 方面的基本知識。在這一節,將討論一些高級問題,當您開始 pickle 複雜對象時,會遇到這些問題,其中包括定製類的實例。幸運的是,Python 可以很容易地處理這種情形。
  
  可移植性
  從空間和時間上說,Pickle 是可移植的。換句話說,pickle 文件格式獨立於機器的體系結構,這意味著,例如,可以在 Linux 下創建一個 pickle,然後將它發送到在 Windows 或 Mac OS 下運行的 Python 程序。並且,當升級到更新版本的 Python 時,不必擔心可能要廢棄已有的 pickle。Python 開發人員已經保證 pickle 格式將可以向後兼容 Python 各個版本。事實上,在 pickle 模塊中提供了有關目前以及所支持的格式方面的詳細信息:
  
  清單 3. 檢索所支持的格式
  >>> pickle.format_version
  '1.3'
  >>> pickle.compatible_formats
  ['1.0', '1.1', '1.2']
  
  多個引用,同一對象
  在 Python 中,變數是對象的引用。同時,也可以用多個變數引用同一個對象。經證明,Python 在用經過 pickle 的對象維護這種行為方面絲毫沒有困難,如清單 4 所示:
  
  清單 4. 對象引用的維護
  >>> a = [1, 2, 3]
  >>> b = a
  >>> a
  [1, 2, 3]
  >>> b
  [1, 2, 3]
  >>> a.append(4)
  >>> a
  [1, 2, 3, 4]
  >>> b
  [1, 2, 3, 4]
  >>> c = pickle.dumps((a, b))
  >>> d, e = pickle.loads(c)
  >>> d
  [1, 2, 3, 4]
  >>> e
  [1, 2, 3, 4]
  >>> d.append(5)
  >>> d
  [1, 2, 3, 4, 5]
  >>> e
  [1, 2, 3, 4, 5]
  
  循環引用和遞歸引用
  可以將剛才演示過的對象引用支持擴展到循環引用(兩個對象各自包含對對方的引用)和遞歸引用(一個對象包含對其自身的引用)。下面兩個清單著重顯示這種能力。我們先看一下遞歸引用:
  
  清單 5. 遞歸引用
  >>> l = [1, 2, 3]
  >>> l.append(l)
  >>> l
  [1, 2, 3, [...]]
  >>> l[3]
  [1, 2, 3, [...]]
  >>> l[3][3]
  [1, 2, 3, [...]]
  >>> p = pickle.dumps(l)
  >>> l2 = pickle.loads(p)
  >>> l2
  [1, 2, 3, [...]]
  >>> l2[3]
  [1, 2, 3, [...]]
  >>> l2[3][3]
  [1, 2, 3, [...]]
  
  現在,看一個循環引用的示例:
  
  清單 6. 循環引用
  >>> a = [1, 2]
  >>> b = [3, 4]
  >>> a.append(b)
  >>> a
  [1, 2, [3, 4]]
  >>> b.append(a)
  >>> a
  [1, 2, [3, 4, [...]]]
  >>> b
  [3, 4, [1, 2, [...]]]
  >>> a[2]
  [3, 4, [1, 2, [...]]]
  >>> b[2]
  [1, 2, [3, 4, [...]]]
  >>> a[2] is b
  1
  >>> b[2] is a
  1
  >>> f = file('temp.pkl', 'w')
  >>> pickle.dump((a, b), f)
  >>> f.close()
  >>> f = file('temp.pkl', 'r')
  >>> c, d = pickle.load(f)
  >>> f.close()
  >>> c
  [1, 2, [3, 4, [...]]]
  >>> d
  [3, 4, [1, 2, [...]]]
  >>> c[2]
  [3, 4, [1, 2, [...]]]
  >>> d[2]
  [1, 2, [3, 4, [...]]]
  >>> c[2] is d
  1
  >>> d[2] is c
  1
  
  注意,如果分別 pickle 每個對象,而不是在一個元組中一起 pickle 所有對象,會得到略微不同(但很重要)的結果,如清單 7 所示:
  
  清單 7. 分別 pickle vs. 在一個元組中一起 pickle
  >>> f = file('temp.pkl', 'w')
  >>> pickle.dump(a, f)
  >>> pickle.dump(b, f)
  >>> f.close()
  >>> f = file('temp.pkl', 'r')
  >>> c = pickle.load(f)
  >>> d = pickle.load(f)
  >>> f.close()
  >>> c
  [1, 2, [3, 4, [...]]]
  >>> d
  [3, 4, [1, 2, [...]]]
  >>> c[2]
  [3, 4, [1, 2, [...]]]
  >>> d[2]
  [1, 2, [3, 4, [...]]]
  >>> c[2] is d
  0
  >>> d[2] is c
  0
  
  相等,但並不總是相同
  正如在上一個示例所暗示的,只有在這些對象引用內存中同一個對象時,它們才是相同的。在 pickle 情形中,每個對象被恢復到一個與原來對象相等的對象,但不是同一個對象。換句話說,每個 pickle 都是原來對象的一個副本:
  
  清單 8. 作為原來對象副本的被恢復的對象
  >>> j = [1, 2, 3]
  >>> k = j
  >>> k is j
  1
  >>> x = pickle.dumps(k)
  >>> y = pickle.loads(x)
  >>> y
  [1, 2, 3]
  >>> y == k
  1
  >>> y is k
  0
  >>> y is j
  0
  >>> k is j
  1
  
  同時,我們看到 Python 能夠維護對象之間的引用,這些對象是作為一個單元進行 pickle 的。然而,我們還看到分別調用 dump() 會使 Python 無法維護對在該單元外部進行 pickle 的對象的引用。相反,Python 複製了被引用對象,並將副本和被 pickle 的對象存儲在一起。對於 pickle 和恢復單個對象層次結構的應用程序,這是沒有問題的。但要意識到還有其它情形。
  
  值得指出的是,有一個選項確實允許分別 pickle 對象,並維護相互之間的引用,只要這些對象都是 pickle 到同一文件即可。pickle 和 cPickle 模塊提供了一個 Pickler(與此相對應是 Unpickler),它能夠跟蹤已經被 pickle 的對象。通過使用這個 Pickler,將會通過引用而不是通過值來 pickle 共享和循環引用:
  
  清單 9. 維護分別 pickle 的對象間的引用
  >>> f = file('temp.pkl', 'w')
  >>> pickler = pickle.Pickler(f)
  >>> pickler.dump(a)
  
  >>> pickler.dump(b)
  
  >>> f.close()
  >>> f = file('temp.pkl', 'r')
  >>> unpickler = pickle.Unpickler(f)
  >>> c = unpickler.load()
  >>> d = unpickler.load()
  >>> c[2]
  [3, 4, [1, 2, [...]]]
  >>> d[2]
  [1, 2, [3, 4, [...]]]
  >>> c[2] is d
  1
  >>> d[2] is c
  1
  
  不可 pickle 的對象
  一些對象類型是不可 pickle 的。例如,Python 不能 pickle 文件對象(或者任何帶有對文件對象引用的對象),因為 Python 在 unpickle 時不能保證它可以重建該文件的狀態(另一個示例比較難懂,在這類文章中不值得提出來)。試圖 pickle 文件對象會導致以下錯誤:
  
  清單 10. 試圖 pickle 文件對象的結果
  >>> f = file('temp.pkl', 'w')
  >>> p = pickle.dumps(f)
  Traceback (most recent call last):
  File "", line 1, in ?
  File "/usr/lib/python2.2/copy_reg.py", line 57, in _reduce
  raise TypeError, "can't pickle %s objects" % base.__name__
  TypeError: can't pickle file objects
  
  類實例
  與 pickle 簡單對象類型相比,pickle 類實例要多加留意。這主要由於 Python 會 pickle 實例數據(通常是 _dict_ 屬性)和類的名稱,而不會 pickle 類的代碼。當 Python unpickle 類的實例時,它會試圖使用在 pickle 該實例時的確切的類名稱和模塊名稱(包括任何包的路徑前綴)導入包含該類定義的模塊。另外要注意,類定義必須出現在模塊的最頂層,這意味著它們不能是嵌套的類(在其它類或函數中定義的類)。
  
  當 unpickle 類的實例時,通常不會再調用它們的 _init_() 方法。相反,Python 創建一個通用類實例,並應用已進行過 pickle 的實例屬性,同時設置該實例的 _class_ 屬性,使其指向原來的類。
  
  對 Python 2.2 中引入的新型類進行 unpickle 的機制與原來的略有不同。雖然處理的結果實際上與對舊型類處理的結果相同,但 Python 使用 copy_reg 模塊的 _reconstructor() 函數來恢復新型類的實例。
  
  如果希望對新型或舊型類的實例修改預設的 pickle 行為,則可以定義特殊的類的方法 _getstate_() 和 _setstate_(),在保存和恢復類實例的狀態信息期間,Python 會調用這些方法。在以下幾節中,我們會看到一些示例利用了這些特殊的方法。
  
  現在,我們看一個簡單的類實例。首先,創建一個 persist.py 的 Python 模塊,它包含以下新型類的定義:
  
  清單 11. 新型類的定義
  class Foo(object):
  
  def __init__(self, value):
  self.value = value
  
  現在可以 pickle Foo 實例,並看一下它的表示:
  
  清單 12. pickle Foo 實例
  >>> import cPickle as pickle
  >>> from Orbtech.examples.persist import Foo
  >>> foo = Foo('What is a Foo?')
  >>> p = pickle.dumps(foo)
  >>> print p
  ccopy_reg
  _reconstructor
  p1
  (cOrbtech.examples.persist
  Foo
  p2
  c__builtin__
  object
  p3
  NtRp4
  (dp5
  S'value'
  p6
  S'What is a Foo?'
  sb.
  >>>
  
  可以看到這個類的名稱 Foo 和全限定的模塊名稱 Orbtech.examples.persist 都存儲在 pickle 中。如果將這個實例 pickle 成一個文件,稍後再 unpickle 它或在另一台機器上 unpickle,則 Python 會試圖導入 Orbtech.examples.persist 模塊,如果不能導入,則會拋出異常。如果重命名該類和該模塊或者將該模塊移到另一個目錄,則也會發生類似的錯誤。
  
  這裡有一個 Python 發出錯誤消息的示例,當我們重命名 Foo 類,然後試圖裝入先前進行過 pickle 的 Foo 實例時會發生該錯誤:
  
  清單 13. 試圖裝入一個被重命名的 Foo 類的經過 pickle 的實例
  >>> import cPickle as pickle
  >>> f = file('temp.pkl', 'r')
  >>> foo = pickle.load(f)
  Traceback (most recent call last):
  File "", line 1, in ?
  AttributeError: 'module' object has no attribute 'Foo'
  
  在重命名 persist.py 模塊之後,也會發生類似的錯誤:
  
  清單 14. 試圖裝入一個被重命名的 persist.py 模塊的經過 pickle 的實例
  >>> import cPickle as pickle
  >>> f = file('temp.pkl', 'r')
  >>> foo = pickle.load(f)
  Traceback (most recent call last):
  File "", line 1, in ?
  ImportError: No module named persist
  
  我們會在下面模式改進這一節提供一些技術來管理這類更改,而不會破壞現有的 pickle。
  
  特殊的狀態方法
  前面提到對一些對象類型(譬如,文件對象)不能進行 pickle。處理這種不能 pickle 的對象的實例屬性時可以使用特殊的方法(_getstate_() 和 _setstate_())來修改類實例的狀態。這裡有一個 Foo 類的示例,我們已經對它進行了修改以處理文件對象屬性:
  
  清單 15. 處理不能 pickle 的實例屬性
  class Foo(object):
  
  def __init__(self, value, filename):
  self.value = value
  self.logfile = file(filename, 'w')
  
  def __getstate__(self):
  """Return state values to be pickled."""
  f = self.logfile
  return (self.value, f.name, f.tell())
  
  def __setstate__(self, state):
  """Restore state from the unpickled state values."""
  self.value, name, position = state
  f = file(name, 'w')
  f.seek(position)
  self.logfile = f
  
  pickle Foo 的實例時,Python 將只 pickle 當它調用該實例的 _getstate_() 方法時返回給它的值。類似的,在 unpickle 時,Python 將提供經過 unpickle 的值作為參數傳遞給實例的 _setstate_() 方法。在 _setstate_() 方法內,可以根據經過 pickle 的名稱和位置信息來重建文件對象,並將該文件對象分配給這個實例的 logfile 屬性。
  
  模式改進
  隨著時間的推移,您會發現自己必須要更改類的定義。如果已經對某個類實例進行了 pickle,而現在又需要更改這個類,則您可能要檢索和更新那些實例,以便它們能在新的類定義下繼續正常工作。而我們已經看到在對類或模塊進行某些更改時,會出現一些錯誤。幸運的是,pickle 和 unpickle 過程提供了一些 hook,我們可以用它們來支持這種模式改進的需要。
  
  在這一節,我們將探討一些方法來預測常見問題以及如何解決這些問題。由於不能 pickle 類實例代碼,因此可以添加、更改和除去方法,而不會影響現有的經過 pickle 的實例。出於同樣的原因,可以不必擔心類的屬性。您必須確保包含類定義的代碼模塊在 unpickle 環境中可用。同時還必須為這些可能導致 unpickle 問題的更改做好規劃,這些更改包括:更改類名、添加或除去實例的屬性以及改變類定義模塊的名稱或位置。
  
  類名的更改
  要更改類名,而不破壞先前經過 pickle 的實例,請遵循以下步驟。首先,確保原來的類的定義沒有被更改,以便在 unpickle 現有實例時可以找到它。不要更改原來的名稱,而是在與原來類定義所在的同一個模塊中,創建該類定義的一個副本,同時給它一個新的類名。然後使用實際的新類名來替代 NewClassName,將以下方法添加到原來類的定義中:
  
  清單 16. 更改類名:添加到原來類定義的方法
  def __setstate__(self, state):
  self.__dict__.update(state)
  self.__class__ = NewClassName
  
  當 unpickle 現有實例時,Python 將查找原來類的定義,並調用實例的 _setstate_() 方法,同時將給新的類定義重新分配該實例的 _class_ 屬性。一旦確定所有現有的實例都已經 unpickle、更新和重新 pickle 后,可以從源代碼模塊中除去舊的類定義。
  
  屬性的添加和刪除
  這些特殊的狀態方法 _getstate_() 和 _setstate_() 再一次使我們能控制每個實例的狀態,並使我們有機會處理實例屬性中的更改。讓我們看一個簡單的類的定義,我們將向其添加和除去一些屬性。這是是最初的定義:
  
  清單 17. 最初的類定義
  class Person(object):
  
  def __init__(self, firstname, lastname):
  self.firstname = firstname
  self.lastname = lastname
  
  假定已經創建並 pickle 了 Person 的實例,現在我們決定真的只想存儲一個名稱屬性,而不是分別存儲姓和名。這裡有一種方式可以更改類的定義,它將先前經過 pickle 的實例遷移到新的定義:
  
  清單 18. 新的類定義
  class Person(object):
  
  def __init__(self, fullname):
  self.fullname = fullname
  
  def __setstate__(self, state):
  if 'fullname' not in state:
  first = '
  last = '
  if 'firstname' in state:
  first = state['firstname']
  del state['firstname']
  if 'lastname' in state:
  last = state['lastname']
  del state['lastname']
  self.fullname = " ".join([first, last]).strip()
  self.__dict__.update(state)
  
  在這個示例,我們添加了一個新的屬性 fullname,併除去了兩個現有的屬性 firstname 和 lastname。當對先前進行過 pickle 的實例執行 unpickle 時,其先前進行過 pickle 的狀態會作為字典傳遞給 _setstate_(),它將包括 firstname 和 lastname 屬性的值。接下來,將這兩個值組合起來,並將它們分配給新屬性 fullname。在這個過程中,我們刪除了狀態字典中舊的屬性。更新和重新 pickle 先前進行過 pickle 的所有實例之後,現在可以從類定義中除去 _setstate_() 方法。
  
  模塊的修改
  在概念上,模塊的名稱或位置的改變類似於類名稱的改變,但處理方式卻完全不同。那是因為模塊的信息存儲在 pickle 中,而不是通過標準的 pickle 介面就可以修改的屬性。事實上,改變模塊信息的唯一辦法是對實際的 pickle 文件本身執行查找和替換操作。至於如何確切地去做,這取決於具體的操作系統和可使用的工具。很顯然,在這種情況下,您會想備份您的文件,以免發生錯誤。但這種改動應該非常簡單,並且對二進位 pickle 格式進行更改與對文本 pickle 格式進行更改應該一樣有效。
  
  結束語
  對象持久性依賴於底層編程語言的對象序列化能力。對於 Python 對象即意味著 pickle。Python 的 pickle 為 Python 對象有效的持久性管理提供了健壯的和可靠的基礎。在下面的參考資料中,您將會找到有關建立在 Python pickle 能力之上的系統的信息。

[火星人 ] LINUX應用技巧,序列化存儲Python對象已經有709次圍觀

http://coctec.com/docs/linux/show-post-189851.html