創(chuàng)新互聯(lián)www.cdcxhl.cn八線動(dòng)態(tài)BGP香港云服務(wù)器提供商,新人活動(dòng)買多久送多久,劃算不套路!
創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、成都外貿(mào)網(wǎng)站建設(shè)公司、昭通網(wǎng)絡(luò)推廣、重慶小程序開發(fā)、昭通網(wǎng)絡(luò)營銷、昭通企業(yè)策劃、昭通品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們大的嘉獎(jiǎng);創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供昭通建站搭建服務(wù),24小時(shí)服務(wù)熱線:028-86922220,官方網(wǎng)址:www.cdcxhl.com這篇文章將為大家詳細(xì)講解有關(guān)Python中的閉包與裝飾器是什么,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
函數(shù)的裝飾器可以以某種方式增強(qiáng)函數(shù)的功能,如在 Flask 中可使用 @app.route('/') 為視圖函數(shù)添加路由,是一種十分強(qiáng)大的功能。在表現(xiàn)形式上,函數(shù)裝飾器為一種嵌套函數(shù),這其中會(huì)涉及到閉包的概念。而在嵌套函數(shù)之間,外部函數(shù)中的變量相對(duì)于內(nèi)部函數(shù)而言為自由變量,使用時(shí)可能需要借助于 nonlocal 關(guān)鍵字進(jìn)行聲明。
nonlocal 聲明
按變量的作用域進(jìn)行分類,Python 中的變量可分為「全局變量」、「局部變量」以及「自由變量」。一般而言,Python 中使用變量前不需要聲明變量,但假定在函數(shù)體中賦值的變量為局部變量~除非顯示使用 global 將在函數(shù)中賦值的變量聲明為全局變量!
而自由變量則是存在于嵌套函數(shù)中的一個(gè)概念~定義在其他函數(shù)內(nèi)部的函數(shù)被稱之為嵌套函數(shù) nested function ,嵌套函數(shù)可以訪問封閉范圍內(nèi)(外部函數(shù))的變量。嵌套函數(shù)不可以在函數(shù)外直接訪問。
在 Python 中,非本地變量默認(rèn)僅可讀取,在修改時(shí)必須顯式指出其為非本地變量~自由變量 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
未加入全局變量和自由變量聲明時(shí)且使用賦值操作時(shí),inner 函數(shù)的變量 ga, nb 默認(rèn)為局部變量,會(huì)報(bào)錯(cuò);如注釋掉 ga += 1 后同樣會(huì)報(bào)錯(cuò):
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 分別為「全局變量」和「自由變量」,此時(shí)如預(yù)期運(yùn)行!
閉包
函數(shù)內(nèi)的函數(shù)以及其自由變量形成閉包。也即閉包是一種保留定義函數(shù)時(shí)存在的自由變量的綁定的函數(shù)~這樣在調(diào)用函數(shù)時(shí),綁定的自由變量依舊可用。
閉包可以避免全局變量的使用以及提供某種形式的數(shù)據(jù)隱藏。當(dāng)函數(shù)中的變量和函數(shù)較少且其中某個(gè)功能常用時(shí),使用閉包來進(jìn)行封裝。當(dāng)變量和函數(shù)更加復(fù)雜時(shí),則使用類來實(shí)現(xiàn)。
# 計(jì)算移動(dòng)平均值的函數(shù) def make_averager(): series = [] def averager(new_value): series.append(new_value) total = sum(series) return total/len(series) return averager
那么此時(shí),make_averager() 函數(shù)的第二行 series = [] 到第七行 return total/len(series) 為閉包,變量 series 為 averager() 函數(shù)中的自由變量!
# avg 為一個(gè) averager 函數(shù)對(duì)象 ~ 含自由變量的綁定 >>> avg = make_averager() >>> avg(10) 10.0 >>> avg(11) 10.5 >>> avg(12) 11 # 創(chuàng)建另一個(gè) averager 函數(shù)對(duì)象 >>> 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]
函數(shù)對(duì)象通過 __closure__ 屬性 —— 返回 cell 對(duì)象元祖(函數(shù)中有多少嵌套函數(shù)則該元祖的長度有多長),生成該對(duì)象的函數(shù)被稱之為閉包函數(shù)。
func.__closure__[0].cell_contents: 訪問存儲(chǔ)在 cell 對(duì)象中值。
裝飾器
裝飾器本身是一個(gè)可調(diào)用的對(duì)象~函數(shù)或類,其參數(shù)為另一個(gè)函數(shù)(被裝飾的函數(shù))。裝飾器可能會(huì)處理被裝飾的函數(shù)(如添加一些功能)然后將之返回,或者將之替換為另一個(gè)函數(shù)或可調(diào)用對(duì)象。這也被稱之為元編程 metaprogramming —— 在編譯時(shí)改變函數(shù)功能。
>>> def make_pretty(func): ... def inner(): ... print("I got decorated!", end='\t') ... func() ... return inner ... >>> def ordinary(): ... print("I am ordinary!") # 用 make_pretty 函數(shù)裝飾 ordinary 函數(shù) >>> pretty = make_pretty(ordinary) >>> pretty() I got decorated! I am ordinary!
可以作為裝飾器的函數(shù)內(nèi)部都有嵌套的功能函數(shù)(用以實(shí)現(xiàn)主要功能),并返回內(nèi)部的嵌套函數(shù)。
@make_pretty def ordinary(): print("I am ordinary!") # 等價(jià)于 def ordinary(): print("I am ordinary!") ordianry = make_pretty(ordinary)
make_pretty(func) 是一個(gè)最簡單的裝飾器,它接受一個(gè)函數(shù)為其參數(shù);內(nèi)部定義了一個(gè) inner() 函數(shù)~輸出 "I got decorated!" 后執(zhí)行被裝飾函數(shù)(此時(shí) func 為 inner 閉包中的自由變量);然后返回內(nèi)部函數(shù) inner。
此時(shí),對(duì)于被裝飾的函數(shù) ordinary 而言,此時(shí)是 inner 的引用:
>>> ordinary() I got decorated! I am ordinary! >>> ordinary.inner at 0x10aeaa1e0>
除了最簡單的裝飾器之外,還可以將多個(gè)裝飾器疊放使用
疊放裝飾器
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!") # 結(jié)果如下 ''' ****************************** $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Hello world! $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ ****************************** ''' # 等價(jià)于 def printer(msg): print(msg) printer = star(dollar(printer))
關(guān)于Python中的閉包與裝飾器是什么就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。