Python基礎(chǔ)globlal nonlocal和閉包函數(shù)裝飾器語(yǔ)法糖
一、global與nonlocal
1、global
- 在py文件中,一般無(wú)法調(diào)用函數(shù)體內(nèi)變量名,而global可使函數(shù)體代碼內(nèi)的變量名直接在函數(shù)體外部調(diào)用,條件是在需要調(diào)用的代碼體中使用global 調(diào)用需要的變量名
未使用global情況:
# 在外部綁定一個(gè)變量名 name = 'kangkng' # 定義一個(gè)函數(shù)體代碼 def func(): # 函數(shù)體內(nèi)部重新綁定一個(gè)變量名 name = 'zhangzhang' # 調(diào)用函數(shù)func func() # 這時(shí)無(wú)法打印函數(shù)體內(nèi)部的變量名 print(name) ------------------------------------------------------------------------ kangkang
使用global情況:
# 在函數(shù)體內(nèi)部使用global時(shí),可在外部直接調(diào)用函數(shù)內(nèi)部變量名 name = 'kangkng' # 定義一個(gè)函數(shù)體代碼 def func(): # 使用global調(diào)用變量名 global name # 函數(shù)體內(nèi)部重新綁定一個(gè)變量名 name = 'zhangzhang' # 調(diào)用函數(shù)func func() # 外py中打印name print(name) ------------------------------------------------------------------------ zhangzhang
2、nonlocal
- 在函數(shù)嵌套使用時(shí),通常在父代碼體中無(wú)法調(diào)用子代碼中變量名,
而nonlocal的作用是,可以在父代碼中直接調(diào)用子代碼中的變量名,條件是需要在子代碼中使用nonlocal 調(diào)用需要的變量名
未使用nonlocal情況:
# 定義一個(gè)函數(shù)體代碼 def outer(): # 綁定一個(gè)變量名 name = 'kangkang' # 代碼體內(nèi)部再次定義一段函數(shù)體 def subcoat(): # 內(nèi)層中綁定變量名 name = 'zhangzhang' # 在函數(shù)外層打印變量名 print(name) # 調(diào)用外層函數(shù)體代碼 outer() ----------------------------------------------------------------------- kangkang
使用nonlocal情況:
# 在函數(shù)體內(nèi)部使用global時(shí),可在外部直接調(diào)用函數(shù)內(nèi)部變量名 def outer(): # 函數(shù)外層綁定一個(gè)變量名 name = 'kangkang' # 代碼體內(nèi)部再次定義一段函數(shù)體 def subcoat(): # 在函數(shù)體內(nèi)層使用nonlocal,調(diào)用變量名 nonlocal name # 內(nèi)層中綁定變量名 name = 'zhangzhang' # 調(diào)用內(nèi)層函數(shù) subcoat() # 在函數(shù)外層打印變量名 print(name) # 調(diào)用外層函數(shù)體代碼 outer() ---------------------------------------------------------------------- zhangzhang
二、函數(shù)名的多種用法
引言:
? 函數(shù)名就相當(dāng)于變量名,只不過(guò)函數(shù)名綁定的是一段函數(shù)體代碼,在我們使用這個(gè)函數(shù)名加括號(hào)時(shí)就可以調(diào)用這段代碼體,具體由以下幾種用法:
1、當(dāng)做變量名賦值
def func(): print('我是func函數(shù)體代碼') res = func print(res()) ------------------------------------------------------------------------ 我是func函數(shù)體代碼 None
2、當(dāng)作函數(shù)的參數(shù)
def func(): print('我是func函數(shù)體代碼') def func1(a): print('我是func1函數(shù)體代碼', a) a() func1(func) ------------------------------------------------------------------------ 我是func1函數(shù)體代碼 <function func at 0x000001D0C14D6310> 我是func函數(shù)體代碼
3、當(dāng)作函數(shù)的返回值
def func(): print('我是func函數(shù)體代碼') def func1(): print('我是func1函數(shù)體代碼') return func res = func1() print(res) res() ------------------------------------------------------------------------ 我是func1函數(shù)體代碼 <function func at 0x00000218F95B6310> 我是func函數(shù)體代碼
4、當(dāng)作容器類型的數(shù)據(jù)
def spring(): print('我是春季,生機(jī)盎然') def summer(): print('我是夏季,活力四射') def autumn(): print('我是秋季,翩翩起舞') def winter(): print('我是冬季,大雪紛飛') while True: season_dict = { '1': spring, '2': summer, '3': autumn, '4': winter } season_select = input('根據(jù)編號(hào),選擇您喜歡的季節(jié)>>>:').strip() if season_select in season_dict: season_dict.get(season_select)() else: print('你選擇的編號(hào)不存在') ------------------------------------------------------------------------
三、閉包函數(shù)
1、什么是閉包函數(shù)
一個(gè)函數(shù)的返回值是另外一個(gè)函數(shù),返回的函數(shù)調(diào)用父函數(shù)內(nèi)部的變量,如果返回的函數(shù)在外部被執(zhí)行,就產(chǎn)生了閉包
2、閉包函數(shù)需滿足的條件
滿足以下兩個(gè)條件的就是閉包函數(shù):
條件一:定義在函數(shù)內(nèi)部的函數(shù)
條件二:用到了外部函數(shù)空間名稱中的名子
3、閉包函數(shù)的作用
作用:使函數(shù)外部能夠調(diào)用函數(shù)內(nèi)部放入屬性和方法
缺點(diǎn):閉包操作導(dǎo)致整個(gè)函數(shù)的內(nèi)部環(huán)境被長(zhǎng)久保存,占用大量?jī)?nèi)存
4、閉包函數(shù)的實(shí)際應(yīng)用
1.函數(shù)內(nèi)部變量名在外部被訪問(wèn)
def fun1(): name = 'python' def inner(): print(name) return inner result = fun1() result() ------------------------------------------------------------------------ python
2.函數(shù)體內(nèi)部函數(shù)體代碼可以通過(guò)外部訪問(wèn)
def fun2(): def inner(): print("執(zhí)行了內(nèi)部函數(shù)inner") def all(): return inner return all result = fun2() result()() ------------------------------------------------------------------------ 執(zhí)行了內(nèi)部函數(shù)inner
四、裝飾器
? 當(dāng)我們需要將一段函數(shù)體代碼在不改變調(diào)用方式和源代碼的情況下,需要給這個(gè)段代碼添加新的功能時(shí),這時(shí)候我們就需要給這段代碼安裝一個(gè)裝飾器,裝飾器是指將這段代碼封裝在閉包函數(shù)內(nèi),來(lái)達(dá)到既能滿足上述條件,又能增加新的功能的條件
概念
- 在不修改被裝飾對(duì)象源代碼和調(diào)用方式的情況下給被裝飾的對(duì)象添加新的功能
本質(zhì)
- 并不是一門新的技術(shù),而是由函數(shù)參數(shù)、名稱空間、函數(shù)名多種用法、閉包函數(shù)組合到一起的效果
口訣
- 對(duì)修改封閉,對(duì)擴(kuò)展開放
1、裝飾器推導(dǎo)流程
1、首先定義一段函數(shù)體代碼,當(dāng)我們給這段函數(shù)傳入指定的參數(shù)時(shí),他就會(huì)暫停一秒,然后運(yùn)行,使它在運(yùn)行結(jié)束后,能夠統(tǒng)計(jì)它的運(yùn)行時(shí)間
import time def index(a, b): time.sleep(1) print(index,a, b)
2、通常,我們只需要在這段代碼運(yùn)行前打印一個(gè)時(shí)間戳,運(yùn)行后再次打印一個(gè)時(shí)間戳,在這段代碼運(yùn)行結(jié)束后通過(guò)前后時(shí)間的插值就能統(tǒng)計(jì)出這段代碼的運(yùn)行時(shí)間,但這種辦法使用起來(lái)比較麻煩且只能使用一次
方法一: import time def index(a, b): start = time.time() time.sleep(1) print(index, a, b) end = time.time() print(end - start) index(1,2) 方式二: import time def index(a, b): time.sleep(1) print(index, a, b) start = time.time() index(1,2) end = time.time() print(end - start)
3、通過(guò)上述方法的方式二,我們可以得出將函數(shù)名包裹在統(tǒng)計(jì)時(shí)間功能代碼內(nèi),這樣在調(diào)用時(shí)相對(duì)便捷,進(jìn)一步思考,若將這段代碼使用函數(shù)封包,那樣在調(diào)用時(shí)就可以更為便捷,在以后統(tǒng)計(jì)該代碼時(shí),只需要調(diào)用封包這段代碼的函數(shù)名就可以直接統(tǒng)計(jì)這段代碼的運(yùn)行時(shí)間
import time def index(a, b): time.sleep(1) print(index, a, b) def time_(): start = time.time() index() end = time.time() print(end - start) time_() ------------------------------------------------------------------------ Traceback (most recent call last): File "D:/pytcharm項(xiàng)目文件路徑/38/11.py", line 297, in <module> time_() File "D:/pytcharm項(xiàng)目文件路徑/38/11.py", line 293, in time_ index() TypeError: index() missing 2 required positional arguments: 'a' and 'b'
4、雖然這種方式可以行得通,但只能針對(duì)沒(méi)有參數(shù)的函數(shù)體代碼,若這段代碼需要傳參者無(wú)法運(yùn)行,并直接報(bào)錯(cuò)。再次進(jìn)一步思考,只需要將封包的這段函數(shù)設(shè)置為有參函數(shù)就可解決這個(gè)問(wèn)題
import time def index(a, b): time.sleep(1) print(index, a, b) def core(a,b): start = time.time() index(a, b) end = time.time() print(end - start) core(1, 2) ------------------------------------------------------------------------ <function index at 0x000001F4A0026310> 1 2 1.0047826766967773
5、由上推導(dǎo)可看出,雖然此功能可以更為便捷的統(tǒng)計(jì)代碼執(zhí)行時(shí)間,但若是源代碼的參數(shù)需要修改則封包它的參數(shù)也需要修改,這時(shí)我們可聯(lián)想到將參數(shù)修改為可變長(zhǎng)參數(shù),就不會(huì)出現(xiàn)這個(gè)問(wèn)題
import time def index(a, b): time.sleep(1) print(index, a, b) def core(*args,**kwargs): start = time.time() index(*args, **kwargs) end = time.time() print(end - start) core(1,2) ------------------------------------------------------------------------ <function index at 0x000002ECDD4E6310> 1 2 1.004744529724121
6、這樣無(wú)論源代碼參數(shù)如何修改,我們都可以進(jìn)行傳參,雖然這個(gè)問(wèn)題解決了,但考慮使用的廣泛性,若有其他函數(shù)體也需要用到這個(gè)功能時(shí),還需要重新修改封包內(nèi)代碼,這時(shí),我們可以使用閉包的方式來(lái)滿足這個(gè)條件
import time def index(a, b): time.sleep(1) print(index, a, b) def func(x, y, z): time.sleep(2) print(func, x, y, z) def outer(index): def core(*args, **kwargs): start = time.time() index(*args, **kwargs) end = time.time() print(end - start) return core res = outer(func) res(1, 2, 3) ------------------------------------------------------------------------ <function func at 0x0000018C23686670> 1 2 3 2.00856614112854
7、通過(guò)將源代碼函數(shù)名放至閉包函數(shù)參數(shù)內(nèi),就可以達(dá)到可以調(diào)動(dòng)任何函數(shù)體代碼都可以執(zhí)行此功能的方法,但并未滿足閉包函數(shù)的條件,源代碼的調(diào)用方式改變了,這時(shí)我們可以通過(guò)將原函數(shù)體代碼賦值的方式來(lái)達(dá)到調(diào)用方式和源代碼都未改變的情況下來(lái)增加此功能
import time def index(a, b): time.sleep(1) print(index, a, b) def func(x, y, z): time.sleep(2) print(func, x, y, z) def outer(index): def core(*args, **kwargs): start = time.time() index(*args, **kwargs) end = time.time() print(end - start) return core index = outer(index) index(1,2) func = outer(func) func(1, 2, 3) ------------------------------------------------------------------------ <function outer.<locals>.core at 0x0000026C17F58280> 1 2 1.004807710647583 <function outer.<locals>.core at 0x0000026C17F58940> 1 2 3 2.0077626705169678
8、雖然上述推導(dǎo)過(guò)程都已滿足裝飾器條件,但是考慮到源代碼有返回值的情況,我們沒(méi)有并沒(méi)有獲取,這時(shí)在進(jìn)一步推導(dǎo),可在裝飾器函數(shù)內(nèi)部調(diào)用源代碼函數(shù)名的位置設(shè)置一個(gè)變量名用于接收返回值,傳給裝飾器底層return用于接收即可解決這個(gè)問(wèn)題
import time def index(a, b): time.sleep(1) print(index, a, b) return 'index' def func(x, y, z): time.sleep(2) print(func, x, y, z) return 'func' def outer(index): def core(*args, **kwargs): start = time.time() res = index(*args, **kwargs) end = time.time() print(end - start) return res return core index = outer(index) res = index(1,2) print(res) func = outer(func) res = func(1, 2, 3) print(res) ------------------------------------------------------------------------ <function outer.<locals>.core at 0x0000020C50A78280> 1 2 1.0050580501556396 index <function outer.<locals>.core at 0x0000020C50A78940> 1 2 3 2.0094454288482666 func
2、裝飾器語(yǔ)法糖
什么是裝飾器語(yǔ)法糖
當(dāng)我們使用裝飾器調(diào)用被裝飾的函數(shù)體代碼時(shí),總是需要在調(diào)用前通過(guò)賦值的方式來(lái)調(diào)用,這樣的方式相對(duì)比較麻煩,這時(shí)我們就可以用到裝飾器語(yǔ)法糖來(lái)節(jié)省時(shí)間和代碼
語(yǔ)法糖的使用方法和條件
用法:在源代碼函數(shù)體上方使用@加裝飾器函數(shù)名
條件:源代碼需在裝飾器下方
具體用法
import time def outer(index): def core(*args, **kwargs): start = time.time() res = index(*args, **kwargs) end = time.time() print(end - start) return res return core @outer def index(a, b): time.sleep(1) print(index, a, b) return 'index' index(1,2)
3、裝飾器模板
def outer(func): def inner(*args, **kwargs): # 執(zhí)行被裝飾對(duì)象之前可以做的額外操作 res = func(*args, **kwargs) # 執(zhí)行被裝飾對(duì)象之后可以做的額外操作 return res return inner
以上就是Python基礎(chǔ)globlal nonlocal和閉包函數(shù)裝飾器語(yǔ)法糖的詳細(xì)內(nèi)容,更多關(guān)于Python基礎(chǔ)globlal nonlocal的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python中subprocess模塊用法實(shí)例詳解
這篇文章主要介紹了Python中subprocess模塊用法,實(shí)例分析了subprocess模塊的相關(guān)使用技巧,需要的朋友可以參考下2015-05-05Python提取Word中圖片的實(shí)現(xiàn)步驟
本文主要介紹了Python提取Word中圖片的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07Python2.7:使用Pyhook模塊監(jiān)聽鼠標(biāo)鍵盤事件-獲取坐標(biāo)實(shí)例
這篇文章主要介紹了Python2.7:使用Pyhook模塊監(jiān)聽鼠標(biāo)鍵盤事件-獲取坐標(biāo)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03