天天看點

python之閉包與裝飾器

python閉包與裝飾器

閉包

在函數内部定義的函數包含對外部的作用域,而不是全局作用域名字的引用,這樣的函數叫做閉包函數。

示例:

#----------------------------------
name='tom'
def func():
     name='jack'
     def bar():
         print(name)
     return bar  
f = func()     # f = bar
f()        # 調用bar()

#輸出結果:
jack
           

上述代碼運作結果列印的是jack而不是tom,bar這個函數就是閉包函數。

閉包函數屬性:

  • 閉包函數是内部函數
  • 包含對外部作用域而非全局作用域的引用

閉包函數特點:

  • 自帶作用域
  • 延遲計算

注意:

函數的作用域關系在函數定義階段就已經固定,與調用位置無關,無論函數在何處調用,都需要回到定義階段去找對應的作用域關系。

檢視一個函數是否是閉包函數可以使用__closure__方法:
name='tom'
def func():
     name='jack'
     def bar():
         print(name)
     return bar  
f = func()     # f = bar
f()        # 調用bar()
print(f.__closure__)  #如果是閉包函數傳回引用的外部作用域對象
print(f.__closure__[0].cell_contents) 
#傳回閉包函數引用外部作用域的值,[0]就是取第一個對象的值,有多個也可以這樣取出
           

總結

閉包函數的基本形式:

# def 外部函數名():
#     内部函數需要的變量
#     def 内部函數():
#         引用外部變量
#     return 内部函數
           

裝飾器

裝飾器本質上是一個Python函數,它可以讓其他函數在不需要做任何代碼變動的前提下增加額外功能,裝飾器的傳回值也是一個函數對象。概括的講,裝飾器的作用就是為已經存在的函數或對象添加額外的功能,使用裝飾器能夠使用原函數名調用實作除了原來功能之外的擴充功能。

定義比較抽象,下面舉個例子:

def deco(func):
    def wrapper(*args,**kwargs):   #這個就相當于是修飾後的新函數
        print('before')
        res = func(*args,**kwargs)  #意味着傳入函數可以接收可變長參數
        print('after')
        return res    #這個傳回值就是傳入函數的傳回值
    return wrapper

@deco     #将下面的foo作為參數傳入deco(),等同于foo = deco(foo),這時候的foo = wrapper
def foo(x,y):
    print('this is foo')
    return x+y

foo(2,3)     #調用foo其實就是執行wrapper
# print(foo(2,3))    #測試傳回值
           

裝飾器的原則

  • 不能修改被裝飾的函數的源代碼
  • 不能修改被裝飾的函數的調用方式

裝飾器的作用

在不修改被裝飾對象源代碼以及調用方式的前提下為期添加新功能

多個裝飾器調用

@auth     #foo = auth(time(foo))
@time     #foo = time(foo)
def foo():
    pass
           

調用順序可以了解為:先調用auth,再調用time,再調用foo。總結就是從外到内(從上往下)執行,判斷調用關系就是從内到外。相當于給foo函數增加了time功能和auth兩個功能,包了兩層,一層一個功能。

有參裝飾器

上面說的裝飾器函數都是無參裝飾器,還有一種是有參裝飾器,有參裝飾器其實就是在無參裝飾器函數外面再包了一個變量。

示例:

def deco(type):
    def auth(func):
        def wrapper(*args,**kwargs):
            if type == 'file':
                print('file auth')
                res = func(*args,**kwargs)
                return res
            elif type == 'ldap':
                print('ldap auth')
            elif type == 'mysql':
                print('mysql auth')
            else:
                print('other auth')
        return wrapper
    return auth

@deco('file')      #執行deco('file')傳回auth,然後@auth,index = auth(index) 是以最終執行index()還是wrapper()函數,不過不同的是包括了type='file'
def index():
    print('welcome to index')

index()

#執行結果:
file auth
welcome to index
           

轉載于:https://www.cnblogs.com/liao-lin/p/7011492.html