一句話,閉包的作用:將方法存於變數。
至於閉包的原因或者目的,或者說,為什麼將方法存於變數,稍後再說。
為了盡量避免用一大段話描述乙個概念,我們理性一點地把閉包的條件劃分成3個:
外函式中定義了乙個內函式
內函式用了外函式的變數
外函式返回了內函式的引用,or,外函式中直接呼叫了內函式
p.s.
其中外函式和內函式是指巢狀函式中外部函式和內部函式
也正是因為需要巢狀函式,因此不支援的巢狀函式的語言也自然不支援此類閉包
條件3中分成了兩類,更多的情況下是前一類,而後一類(外函式直接呼叫了內函式)的使用更多的是為了保證**的簡潔,而如此地保持簡潔並不一定用閉包。
「talk is cheap, show me your code.」
我始終覺得,在程式設計中,過多的人類語言會產生太多的歧義,甚至還可能會因為所說事物過於抽象而導致聽眾無法將概念理解。
而解決這個問題最好的方法就是看**,程式語言相較於人類語言的優點之一是大幅地降低了語言的歧義。同時,通過多個**例項,人腦會自然而然地將多例項中的共同點提取出來,進而理解抽象的概念。
結合閉包的三個條件,我們來看看閉包的例子:
def outer(b):
def inner(a): # 條件1
print(a + b) # 條件2
return inner # 條件3
# 呼叫
o = outer(1)
o(2)
python的**還是挺簡單的。
一般情況下,在函式結束後,函式中變數等就應該被銷毀,偏偏這個閉包就是個特例 —— o和o2中的1和20都保留著。
o和o2看起來就有那麼一絲熟悉的感覺,它們兩個就像是兩個物件 —— 這兩個「物件」都是從同乙個「類」出來的,而兩個「物件例項」的區別是有乙個加數不一樣,分別是1和20(當然,這兩個變數的引用位址也不同)。
現在,我們把**例子中的第三個條件變一下,即將「外函式返回了內函式的引用」變成「外函式中直接呼叫了內函式」:
def outer(a, b):
def inner(a): # 條件1
print(a + b) # 條件2
inner(b) # 條件3
# 呼叫
此時,整個閉包函式呼叫起來就和乙個普通函式一樣,傳入兩個引數,該print的也如期而至。
只能說,在outer函式內的邏輯過於複雜的時候,inner能把複雜的**「模組化」,再呼叫,能增加簡潔性。這種情況下,一般是inner函式只被呼叫一次,而且只在這裡呼叫,放在這裡也好管理一些。
接下來,我們也鑑賞一下別的語言類似的閉包:
func outer(i int) func() int
}// 呼叫
o := outer(1)
o()
這個golang的例子閉包和python的例子較大的距別是這裡還把內函式換成了匿名的,看起來會爽點。而以下的php的就和python的差不多了。
function outer($str1) ;
return $inner; // 條件3
}// 呼叫
$o = outer("hahaha");
$o("emmm");
看過了上面的例子後,新手對閉包的概念也應該有了一定的理解,甚至有點想法了。
回到最開始的問題,即閉包的原因。
如果說,「將方法存於變數」是閉包的目的,那麼接下來的問題顯而易見:為什麼要將方法存於變數?直接呼叫方法(函式)不好嗎?
再舉開頭的例子:
def outer(b):
def inner(a):
print(a + b)
return inner
o = outer(1)
o(2) # 3
o(100) # 101
o2 = outer(20)
o2(100) # 120
o這個變數對應的閉包儲存了b=1
這個資訊,之後無論是呼叫o(2)
還是o(100)
,b=1
這個資訊依然會存在並和後來的引數一起參與運算。同理,o2這個變數對應的閉包儲存了b=20
這個資訊。
由於退出了函式後,函式並沒有並銷毀,這個閉包的資訊也沒銷毀,因此後續可以利用這些資訊。
為了**的簡潔性和易理解性,我們經常會使用甚至創造一些語法糖。
而在python中,有乙個十分好看的例子就是裝飾器,舉個已經被用爛了的例子,面向切面的登入實現:
# 先實現乙個類似於裝飾器的函式
def decorator(func):
def inner():
print 'before function'
func() # function
print 'after function'
return inner
# 實現乙個假裝在登入的登入函式
def login():
print 'login function complete.'
# 將登入函式「套上」裝飾器
login = decorator(login)
login()
整個過程下來與aop類似,而場景也很常用,如統計函式的執行時常、加入日誌、統一的過濾處理等等。
def operator(o):
def plus(x, y):
print(x + y)
def minus(x, y):
print(x - y)
if o == '+':
return plus
if o == '-':
return minus
def f(x, o, y):
operator(o)(x, y)
閉包能將方法存於變數,且實現一些美妙的東西。
它就像是調味劑,並非不可或缺,但是能錦上添花。
先這樣吧
簡簡單單說個閉包
一句話,閉包的作用 將方法存於變數。至於閉包的原因或者目的,或者說,為什麼將方法存於變數,稍後再說。為了盡量避免用一大段話描述乙個概念,我們理性一點地把閉包的條件劃分成3個 外函式中定義了乙個內函式 內函式用了外函式的變數 外函式返回了內函式的引用,or,外函式中直接呼叫了內函式 p.s.其中外函式...
簡簡單單編譯原理
都說編譯原理挺難,其實它並不像大家想象中的那麼難,it s so easy 總的來說編譯原理可以分為以下幾個知識點 文法的分類 不確定的有限狀態自動機到確定的有限狀態自動機的轉換 正規表示式。掌握了這三個知識點,編譯原理中每個題的道理了,其實編譯原理就是這麼回事。下面具體介紹上面說的三個知識點 1....
簡簡單單寫程式
寫程式這麼多年,總有幾百萬行了。感覺,程式寫的方向,總的來說越來越簡單。乙個函式,簡簡單單幾行就完了,乙個類,簡簡單單幾個公有方法,也就完了。簡單,就不容易出錯,自己看自己的 看昏了的也有,乙個函式幾千行,人的腦子,堆疊顯然不夠用,看了後面,忘了前面,何苦呢。簡單,就好懂,乙個工程完了,心裡其實很發...