日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python闭包与装饰器有啥关系_深入理解Python中的闭包与装饰器

發布時間:2023/12/19 python 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python闭包与装饰器有啥关系_深入理解Python中的闭包与装饰器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

函數的裝飾器可以以某種方式增強函數的功能,如在 Flask 中可使用 @app.route('/') 為視圖函數添加路由,是一種十分強大的功能。在表現形式上,函數裝飾器為一種嵌套函數,這其中會涉及到閉包的概念。而在嵌套函數之間,外部函數中的變量相對于內部函數而言為自由變量,使用時可能需要借助于 nonlocal 關鍵字進行聲明。

nonlocal 聲明

按變量的作用域進行分類,Python 中的變量可分為「全局變量」、「局部變量」以及「自由變量」。一般而言,Python 中使用變量前不需要聲明變量,但假定在函數體中賦值的變量為局部變量~除非顯示使用 global 將在函數中賦值的變量聲明為全局變量!

而自由變量則是存在于嵌套函數中的一個概念~定義在其他函數內部的函數被稱之為嵌套函數 nested function ,嵌套函數可以訪問封閉范圍內(外部函數)的變量。嵌套函數不可以在函數外直接訪問。

在 Python 中,非本地變量默認僅可讀取,在修改時必須顯式指出其為非本地變量~自由變量 nonlocal,全局變量 global。>>> ga = 1

>>> def func():

... nb = 2

... def inner():

... ga += 1

... nb += 2

... print('ga is %s, and nb is %s' % (ga, nb))

... return inner

...

>>> test = func()

Traceback (most recent call last):

...

UnboundLocalError: local variable 'ga' referenced before assignment

未加入全局變量和自由變量聲明時且使用賦值操作時,inner 函數的變量 ga, nb 默認為局部變量,會報錯;如注釋掉 ga += 1 后同樣會報錯:Traceback (most recent call last):

...

UnboundLocalError: local variable 'nb' referenced before assignment

可行改寫如下:>>> ga = 1

>>> def func():

... nb = 2

... def inner():

... global ga

... nonlocal nb

... ga += 1

... nb += 2

... print('ga is %s, and nb is %s' % (ga, nb))

... return inner

...

>>> test = func()

>>> test()

ga is 2, and nb is 4

>>> test()

ga is 3, and nb is 6

通過顯示聲明 ga, nb 分別為「全局變量」和「自由變量」,此時如預期運行!

閉包

函數內的函數以及其自由變量形成閉包。也即閉包是一種保留定義函數時存在的自由變量的綁定的函數~這樣在調用函數時,綁定的自由變量依舊可用。

閉包可以避免全局變量的使用以及提供某種形式的數據隱藏。當函數中的變量和函數較少且其中某個功能常用時,使用閉包來進行封裝。當變量和函數更加復雜時,則使用類來實現。# 計算移動平均值的函數

def make_averager():

series = []

def averager(new_value):

series.append(new_value)

total = sum(series)

return total/len(series)

return averager

那么此時,make_averager() 函數的第二行 series = [] 到第七行 return total/len(series) 為閉包,變量 series 為 averager() 函數中的自由變量!# avg 為一個 averager 函數對象 ~ 含自由變量的綁定

>>> avg = make_averager()

>>> avg(10)

10.0

>>> avg(11)

10.5

>>> avg(12)

11

# 創建另一個 averager 函數對象

>>> avg2 = make_averager()

>>> avg2(1)

1.0

>>> avg2(18)

9.5

# 查看 avg, avg2 自由變量中保存的值

>>> avg.__closure__[0].cell_contents

[10, 11, 12]

>>> avg2.__closure__[0].cell_contents

[1, 18]

函數對象通過 __closure__ 屬性 —— 返回 cell 對象元祖(函數中有多少嵌套函數則該元祖的長度有多長),生成該對象的函數被稱之為閉包函數。

func.__closure__[0].cell_contents: 訪問存儲在 cell 對象中值。

裝飾器

裝飾器本身是一個可調用的對象~函數或類,其參數為另一個函數(被裝飾的函數)。裝飾器可能會處理被裝飾的函數(如添加一些功能)然后將之返回,或者將之替換為另一個函數或可調用對象。這也被稱之為元編程 metaprogramming —— 在編譯時改變函數功能。>>> def make_pretty(func):

... def inner():

... print("I got decorated!", end='')

... func()

... return inner

...

>>> def ordinary():

... print("I am ordinary!")

# 用 make_pretty 函數裝飾 ordinary 函數

>>> pretty = make_pretty(ordinary)

>>> pretty()

I got decorated! I am ordinary!

可以作為裝飾器的函數內部都有嵌套的功能函數(用以實現主要功能),并返回內部的嵌套函數。@make_pretty

def ordinary():

print("I am ordinary!")

# 等價于

def ordinary():

print("I am ordinary!")

ordianry = make_pretty(ordinary)

make_pretty(func) 是一個最簡單的裝飾器,它接受一個函數為其參數;內部定義了一個 inner() 函數~輸出 "I got decorated!" 后執行被裝飾函數(此時 func 為 inner 閉包中的自由變量);然后返回內部函數 inner。

此時,對于被裝飾的函數 ordinary 而言,此時是 inner 的引用:>>> ordinary()

I got decorated! I am ordinary!

>>> ordinary

.inner at 0x10aeaa1e0>

除了最簡單的裝飾器之外,還可以將多個裝飾器疊放使用

疊放裝飾器def star(func):

def inner(*args, **kwargs):

print('*' * 30)

func(*args, **kwargs)

print('*' * 30)

return inner

def dollar(func):

def inner(*args, **kwargs):

print('$' * 30)

func(*args, **kwargs)

print('$' * 30)

return inner

@star

@doller

def printer(msg):

print(msg)

printer("Hello world!")

# 結果如下

'''

******************************

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

Hello world!

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

******************************

'''

# 等價于

def printer(msg):

print(msg)

printer = star(dollar(printer))

總結

以上是生活随笔為你收集整理的python闭包与装饰器有啥关系_深入理解Python中的闭包与装饰器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。