<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            8.9. 全部放在一起

            到了將迄今為止我們已經學過并用得不錯的東西放在一起的時候了。我希望您專心些。

            例 8.20. translate 函數,第 1 部分

            
            def translate(url, dialectName="chef"): 1
                import urllib                       2
                sock = urllib.urlopen(url)          3
                htmlSource = sock.read()           
                sock.close()                       
            
            1 這個 translate 函數有一個可選參數 dialectName,它是一個字符串,指出我們將使用的方言。一會我們就會看到它是如何使用的。
            2 嘿,等一下,在這個函數中有一個 import 語句!它在 Python 中完全合法。您已經習慣了在一個程序的前面看到 import 語句,它意味著導入的模塊在程序的任何地方都是可用的。但您也可以在一個函數中導入模塊,這意味著導入的模塊只能在函數中使用。如果您有一個只能用在一個函數中的模塊,這是一個簡便的方法,使您的代碼更模塊化。(當發現您周末的加班已經變成了一個 800 行的藝術作品,并且決定將其分割成一打可重用的模塊時,您會感謝它的。)
            3 現在我們得到了給定的 URL 源文件

            例 8.21. translate 函數,第 2 部分:奇妙而又奇妙

                parserName = "%sDialectizer" % dialectName.capitalize() 1
                parserClass = globals()[parserName]                     2
                parser = parserClass()                                  3
            
            1 capitalize 是一個我們以前未曾見過的字符串方法;它只是將一個字符串的第一個字母變成大寫,將其它的字母強制變成小寫。再使用字符串格式化,我們就得到了一種方言的名字,并將它轉化為了相應的方言變換器類的名字。如果 dialectName 是字符串 'chef'parserName 將是字符串 'ChefDialectizer'
            2 我們有了一個字符串形式 (parserName) 的類名稱,還有一個 dictionary (globals()) 形式的全局名字空間。合起來后,我們可以得到以前者命名的類的引用。(回想一下,類是對象,并且它們可以像其它對象一樣賦值給一個變量。) 如果 parserName 是字符串 'ChefDialectizer'parserClass 將是類 ChefDialectizer
            3 最后,我們擁有了一個類對象 (parserClass),接著我們想要生成這個類的一個實例。好,我們已經知道如何去做了:像函數一樣調用類。這個類保存在一個局部變量中,但這個事實完全不會有什么影響;我們只是像函數一樣調用這個局部變量,取出這個類的一個實例。如果 parserClass 是類 ChefDialectizerparser 將是類 ChefDialectizer 的一個實例。

            何必這么麻煩?畢竟只有三個 Dialectizer 類;為什么不只使用一個 case 語句? (噢,在 Python 中不存在 case 語句,但為什么不只使用一組 if 語句呢?) 理由之一是:可擴展性。這個 translate 函數完全不用關心我們定義了多少個方言變換器類。設想一下,如果我們明天定義了一個新的 FooDialectizer 類,把 'foo' 作為 dialectName 傳給 translatetranslate 也能工作。

            甚至會更好。設想將 FooDialectizer 放進一個獨立的模塊中,使用 from module import 將其導入。我們已經知道了,這樣會將它包含在 globals() 中 ,所以不用修改 translate ,它仍然可以正確運行,盡管 FooDialectizer 位于一個獨立的文件中。

            現在設想一下方言的名字是從程序外面的某個地方來的,也許是從一個數據庫中,或從一個表格中的用戶輸入的值中。您可以使用任意多的服務端 Python 腳本架構來動態地生成網頁;這個函數將接收在頁面請求的查詢字符串中的一個 URL 和一個方言名字 (兩個都是字符串) ,接著輸出 “翻譯” 后的網頁。

            最后,設想一下,使用了一種插件架構的 Dialectizer 框架。您可以將每個 Dialectizer 類放在分別放在獨立的文件中,在 dialect.py 中只留下 translate 函數。假定一種統一的命名模式,這個 translate 函數能夠動態地從合適的文件中導入合適的類,除了方言名字外什么都不用給出。(雖然您還沒有看過動態導入,但我保證在后面的一章中會涉及到它。) 如果要加入一種新的方言,您只要在插件目錄下加入一個以合適的名字命名的文件 (像 foodialect.py,它包含了 FooDialectizer 類) 。使用方言名 'foo' 來調用這個 translate 函數,將會查找 foodialect.py 模塊,導入 FooDialectizer 類,這樣就行了。

            例 8.22. translate 函數,第 3 部分

                parser.feed(htmlSource) 1
                parser.close()          2
                return parser.output()  3
            
            1 剩下的工作似乎會非常無聊,但實際上,feed 函數執行了全部的轉換工作。我們擁有存在于單個字符串中的全部 HTML 源代碼,所以我們只需要調用 feed 一次。然而,您可以按您的需要經常調用 feed,分析器將不停地進行分析。所以如果我們擔心內存的使用 (或者我們已經知道了將要處理非常巨大的 HTML 頁面) ,我們可以在一個循環中調用它,即我們讀出一點 HTML 字節,就將其送進分析器。結果會是一樣的。
            2 因為 feed 維護著一個內部緩沖區,當您完成時,應該總是調用分析器的 close 方法 (那怕您像我們做的一樣,一次就全部送出) 。否則您可能會發現,輸出丟掉了最后幾個字節。
            3 回想一下,output 是我們在 BaseHTMLProcessor 上定義的函數,用來將所有緩沖的輸出片段連接起來并且以單個字符串返回。

            像這樣,我們已經 “翻譯” 了一個網頁,除了給出一個 URL 和一種方言的名字外,什么都沒有給出。

            進一步閱讀

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线