2010-05-09 91 views
13

我正在使用Dive Into Python 3書學習Python。我喜歡它,但我不明白第6.5節中的example used to introduce ClosuresPython閉包示例代碼

我的意思是,我看到它是如何工作的,我認爲這是真的很酷。但是我沒有看到任何真正的好處:在我看來,通過簡單地在規則文件中逐行閱讀循環,併爲每行讀取進行搜索/替換,可以實現相同的結果。

有人能幫助我:

  • 也不能理解,爲什麼在這個例子中使用閉包提高了代碼(例如,更容易維護,擴展,再利用,或調試?)

  • 或建議一些其他真實代碼示例的來源,其中閉包真正發光?

謝謝!

回答

21

裝飾者是閉包的一個例子。例如,

def decorate(f): 
    def wrapped_function(): 
     print("Function is being called") 
     f() 
     print("Function call is finished") 
    return wrapped_function 

@decorate 
def my_function(): 
    print("Hello world") 

my_function() 

功能wrapped_function是閉合的,因爲它保留訪問在其範圍內的變量 - 特別是,參數f,原始函數。閉包可以讓你訪問它。

閉包也能讓你保持狀態跨越函數調用,而不必求助於類:

def make_counter(): 
    next_value = 0 
    def return_next_value(): 
     nonlocal next_value 
     val = next_value 
     next_value += 1 
     return val 
    return return_next_value 

my_first_counter = make_counter() 
my_second_counter = make_counter() 
print(my_first_counter()) 
print(my_second_counter()) 
print(my_first_counter()) 
print(my_second_counter()) 
print(my_first_counter()) 
print(my_second_counter()) 

此外,綁定方法在技術上封鎖(雖然他們可能的實現方式不同)。結合的方法是類的成員函數與它們的類中烘焙:

import sys 
w = sys.stdout.write 
w("Hello\n") 

w基本上與所述sys.stdout對象的引用的封閉件。

最後,我還沒有讀過那本書,而是快速閱讀了關聯的這一章,我對此非常無動於衷 - 它是如此可怕的迂迴曲折,以至於它對閉包的解釋沒用。這裏

def confmaker(): 
    cf=ini_conf() 
    def clo(*args): 
     return cf.get(*args) 
    return clo 

cfget=confmaker() 

cfget(...) 

ini_conf只調用一次:

+0

謝謝! 我很喜歡使用類似風格和深度的這個答案的Python 3書,但我找不到一個... – max 2010-05-09 18:21:16

2

當您有權訪問整個代碼庫或者您沒有考慮到可重用性時,這可能看起來並不特別有用,但在嘗試將邏輯分離成不同的可重用模塊時,它非常強大和有用。由不同的開發人員並行執行。如果你只是從文件中讀取模式字符串,每個模塊都必須知道這個文件,並傳遞那些令人討厭的模式字符串列表。如果您更改了系統,以使模式字符串來自URL而不是來自文件,那麼它可能會徹底破壞整個代碼庫。另一方面,如果處理邏輯只是簡單地使用回調函數或多個回調函數,然後又有另一個模塊使用文件中的內容動態地構造函數,那麼只有構造函數的組件需要更改。這是能夠動態創建功能的力量。

+0

是;但爲什麼不傳遞字符串列表?一個模塊將處理文件或URL或我們擁有的任何其他輸入源。而程序的其餘部分將採用實際的規則作爲模式字符串列表。 – max 2010-05-09 18:37:11

+0

@ user336527,另一個模塊可以簡單地驗證對象是否符合謂詞列表。它甚至不需要知道這些謂詞是什麼。這簡化了第二個模塊的任務,並且允許重複使用與字符串匹配無關的謂詞。雖然,我會同意,這個例子有點人爲的做法。比這個例子有更好的用例。 – 2010-05-09 22:04:34

+0

謝謝,這讓我對事情更加清楚! – max 2010-05-10 03:18:22

0

讀取一行規則文件線環路由線

線在一個循環

這將通過地面驅動性能。閱讀一次,多次應用。

+0

對不起,我不是很精確。當然,我會將從文件中讀取的模式字符串存儲在列表中,然後始終遍歷該列表。但是如何傳遞一個函數列表比傳遞一個模式字符串列表更好? – max 2010-05-09 18:39:26

2

這裏是一個封閉的使用,獲取配置。在我的理解中,閉包避免了全局變量(如cf),並使用法簡單。

1

尼爾斯-BOM寫入(與編輯):

同樣的結果可以通過線在規則文件中的行只是在讀一環,和做搜索/替換爲讀取每一行來實現。

而事實上,這就是6.5節中的規則放在文件plural4-rules.txt中所實現的。現在將規則作爲字符串保存在文件中,我們的代碼將數據從控制中分離出來。這使項目更容易管理和維護。

尼爾斯的問題促使我勾畫出第6章的發展,努力準確瞭解作者試圖論證。在提供的開發中有很多要學習的經驗教訓,它不僅僅關於閉包,還包括編碼方面的最佳實踐。

的鍛鍊讓我瞭解到發生器可以如何被用來取代替代,那麼抽象,多落網實現。從6.2到6.6的材料的發展足夠教育在這裏草圖。

爲什麼使用閉包在這個例子中提高代碼:

所以我與尼爾斯關於分手的規則成單獨的功能在6.3的賽格瑞進入草圖第二點開始的?

筆者狀態在這一點上:

新增這級別的抽象的價值呢?那麼,還沒有。

還有部分6.4-6.6工作通過。封閉的故事,在這種情況下,建立一個多元化的發電機是一步一步實現的,從一個稱爲複數(名詞)的模塊中的硬編碼規則開始。因此,從第一個相關部分開始,總結本章的結尾部分,我們會得到以下結論。

6.2讓我們使用正則表達式:這裏筆者藉此機會加強和擴大我們與最初的複數函數中硬編碼的複數化規則的正則表達式的理解。

6.3。函數列表:將複數函數中硬編碼的規則抽象爲幾個獨立的函數。這是下一部分的「墊腳石」。但是它也證明了match_sxz()和match_sxz的用法有一個重要的區別。

6.4匹配模式列表:我們創造了個人命名的功能,如配對的匹配和應用,在6.3實際上是多餘的。這些功能都基於相同的模式,並且不會直接調用。在這裏他修改了這段代碼,以便更改規則。這成爲了進一步的抽象層次,規則現在在稱爲模式的變量中被指定爲字符串。多元化規則不再是功能。

6.5模式文件:沒有更多的重複代碼和字符串列表中定義的多元化規則,構建生成器的下一步是將這些字符串放在單獨的文件中。在這裏,它們變得更易於維護,與使用它們的代碼分開。

6.6生成器:生成器是一個通用的plural()函數,用於解析規則文件,檢查匹配項,適用規則並轉到下一條規則。這是關閉的一個例子。

這就是所有的plural()函數必須做的,這就是所有的plural()函數應該做的。

一個相對簡單和美觀的開發,足夠複雜,有用,可擴展到其他類型的問題,尤其是在文本模式識別中。

作者在本教程結束時討論了這個特定解決方案的性能問題。從文件中打開和讀取行會降低性能,尤其是在open()調用數量不斷增加的情況下。他表示,使用迭代器可以獲得更好的性能,本書後面將對此進行考慮。