Python入門(九) 函數-閉包

    在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)

    

    總算寫完了,困了,睡覺了。

相關文章
相關標籤/搜索