• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

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

    發布: 2007-7-04 20:06 | 作者: admin | 來源:  網友評論 | 查看: 11次 | 進入軟件測試論壇討論

    領測軟件測試網

      什么是持久性?
      持久性的基本思想很簡單。假定有一個 Python 程序,它可能是一個管理日常待辦事項的程序,您希望在多次執行這個程序之間可以保存應用程序對象(待辦事項)。換句話說,您希望將對象存儲在磁盤上,便于以后檢索。這就是持久性。要達到這個目的,有幾種方法,每一種方法都有其優缺點。
      
      例如,可以將對象數據存儲在某種格式的文本文件中,譬如 CSV 文件;蛘呖梢杂藐P系數據庫,譬如 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
      &

    [1] [2] 下一頁

    延伸閱讀

    文章來源于領測軟件測試網 http://www.kjueaiud.com/


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備2023014753號-2
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>