在Python中,函數也是一種變量類型,也就是說能夠用變量去保存一個函數。python
def hello(): print("hello") print(type(hello)) >>> <class 'function'>
#將函數對象賦值爲變量func,此時func指向了hello指向的函數對象 func = hello func() #調用函數 >>> hello
經過上面能夠看出,咱們能夠把一個函數賦值爲一個變量,那麼此變量就指向該函數對象。固然,咱們也是能夠修改hello執行的函數對象的,如:編程
def say_hi(): print("Hi") hello = say_hi hello() >>> Hi
把say_hi函數對象賦值爲hello,那麼hello就指向了say_hi函數對象,再也不指向原先的函數對象了,也就沒法再調用原先的函數對象。
閉包
基於函數的上述特性,咱們能夠很容易的實現一個函數功能表,好比咱們常見的http的服務隊請求的處理,會根據請求的方法分別處理:
app
def handle_http_get(): print('handle http get request') def handle_http_post(): print('handle http post request') def handle_http_put(): print('handle http put request') http_handler = {'get': handle_http_get, 'post': handle_http_post, 'put': handle_http_put} #上面分別實現了處理http的get,post,put請求 #當請求的方法爲get時,咱們能夠這麼處理: method = 'get' http_handler[method]() >>> handle http get request
2.閉包Closure
ide
既然函數是對象,那麼就能夠在函數中返回一個函數對象:
函數
def get_func(): def func(): print('inside func') return func f = get_func() # 此時f指向了func函數對象 f() #執行func函數對象 >>> inside func
一個函數與它的環境變量結合在一塊兒,就構成Closure。
post
def power_factory(n): def power(list_arg): for i in range(len(list_arg)): list_arg[i] = list_arg[i]**n return power #計算list中的每一個數的平方 list1 = [1, 2, 3] f1 = power_factory(2) f1(list1) print(list1) f1(list1) print(list1) #計算List中每一個數的立方 list1 = [1, 2, 3] f2 = power_factory(3) f2(list1) print(list1) >>> [1, 4, 9] [1, 16, 81] [1, 8, 27]
對於power函數對象而言,power_factory函數傳遞的參數n就是其環境變量,會保存到函數對象的__closure__屬性中。這樣子每次調用f1函數,執行的都是2的平方操做,因此上面連續兩次調用f1,輸出的都是平方數。若是咱們須要執行立方操做,只須要從新調用power_factory,生成一個環境變量n = 3的閉包。
debug
通常來講,像c編程中的函數,是沒有狀態的,除非在c函數中使用static變量來保存其狀態,而使用閉包,咱們能夠很方便的作到函數都有其本身獨立的環境變量。
調試
3. 裝飾器
code
函數對象有一個__name__屬性,表示函數的名字:
print(max.__name__) >>> max
如咱們前面已經實現了一個hello函數,如今咱們想加強hello函數的功能,在執行hello函數前,加入打印調試信息。在不改變hello函數源碼的前提下,能夠經過閉包來完成。
def debug(func): def wrapper(*args, **kw): print('call %s' % func.__name__) return func(*args, **kw) return wrapper hello = debug(hello) hello() >>> call hello hello
在上述的使用過程當中,須要先執行hello = debug(hello), 感受代碼老是有點怪怪的,爲此Python中引入@語法,簡化使用的過程。
@debug def hello(): print(‘hello') hello() >>> call hello hello
把@debug放在hello的前面,就至關於執行了hello = debug(hello)
若是須要在debug中傳遞參數,則須要使用3層函數定義:
def debug(text): def decorator(func): def wrapper(*args, **kw): print('%s: call %s' % (text, func.__name__)) func(*args, **kw) return wrapper return decorator @debug('debug_info') def hello(): print("hello") hello() >>> debug_info: call hello hello
把@debug('debug_info')放在hello的前面,至關於執行了hello = debug('debug_info')(hello)
總算寫完了,困了,睡覺了。