在以前我寫過一篇博客,講述了python的閉包和裝飾器,python的裝飾器一直是面試熱點,也是python很重要的特性之一,不過我認爲閉包是裝飾器的基礎,比裝飾器擁有更寬廣的概念和做用,因此若是面試官問我關於裝飾器的問題,我都會從閉包的角度去分析裝飾器,關於這個大塊面試官問了我以下幾個問題:什麼是裝飾器?什麼是閉包?閉包和裝飾器的做用?閉包和裝飾器的使用場景?下面從這幾個問題出發,在前一篇博客的基礎之上更加深入的探討關於閉包和裝飾器的知識html
關於閉包的概念,我從網上找了以下幾種說法:python
上面的話語基本涵蓋了閉包的特性,關於這些語句的理解,我仍是先列舉一個很是簡單的例子:面試
# coding="utf-8" def fun(msg): def nested_fun(): print msg return nested_fun new_fun = fun("i like python") new_fun()
上面的代碼首先定義了一個函數fun,在這個函數之中再定義了一個嵌套函數,以後返回了這個函數,在這個函數以外,從新將fun函數包括msg參數賦值給了new_fun,以後執行new_fun()函數,運行這段代碼,能夠發如今console中打印出了i love python這句話。上面的代碼有兩個注意點:1.函數也是一種對象,能夠做爲參數返回和傳遞;2.new_fun=fun("i like python")這句代碼實際上是將new_fun指向了fun函數的返回值nested_fun函數,在執行new_fun函數的時候其實在執行了nested_fun函數,在這個函數中打印出的msg對象其實來自於上層函數,並非本身的本地變量,爲何還會打印出來呢?因此這就是閉包,根據這個例子能夠很好的體會上面列出的幾種說法。
在python中閉包所知足的條件爲:閉包
裝飾器和閉包能夠實現必定的封裝功能,將函數或者變量封裝起來,同時利用他們能夠減小代碼冗餘,減小一些重複工做量。下面舉一個例子,若是如今咱們想實現一個簡單的乘法函數,好比times2(n)函數就是給n*2,times5(n)實現給n乘以5,這個功能可使用默認值很容易的實現,代碼以下:app
def times2(n, x=2): return n * x print times2(3)
可是這有個明顯的缺點,每一個times()函數都須要進行定義細節,如今能夠用閉包來實現,代碼以下:ide
def multiplier(n): def multi(x): return x * n return multi times2 = multiplier(2) times5 = multiplier(5) print times2(4) print times5(4)
這段代碼的美妙你們能夠好好體會一下。
說完了閉包,再說一說裝飾器,裝飾器就是用函數或者類去封裝(裝飾)另外一個對象,裝飾器支持和被封裝的對象相同的接口,因此被裝飾的對象甚至感受不到本身被裝飾了,在python中,裝飾器更多的是一個函數將另外一個函數做爲參數,他會利用閉包來實現整個裝飾功能,和上面舉得閉包的例子不一樣的是,裝飾器利用的是閉包能夠捕獲函數。
裝飾器的經常使用場景以下:函數
下面簡單的列舉一個記錄函數行爲的裝飾器的使用:es5
def logging(func): def wrapper(*args, **kwargs): res = func(*args, **kwargs) print func.__name__, args, kwargs return res return wrapper @logging def fib(n): if n == 1 or n == 0: return 1 return fib(n-1) + fib(n-2) print fib(10)
上面的裝飾器代碼實現了打印被裝飾的函數的執行狀況,你們能夠本身運行。code
語言的美會獲得承認和傳播,好比lamdba函數,瞭解了語言的特性以後,能夠極大的提升工做效率,增長代碼的美感,提升代碼的健壯性。htm