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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

python装饰器作用和功能_python装饰器大详解

發(fā)布時(shí)間:2025/3/11 python 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python装饰器作用和功能_python装饰器大详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一.作用域

在python中,作用域分為兩種:全局作用域和局部作用域。

全局作用域是定義在文件級(jí)別的變量,函數(shù)名。而局部作用域,則是定義函數(shù)內(nèi)部。

關(guān)于作用域,我們要理解兩點(diǎn):

a.在全局不能訪問到局部定義的變量

b.在局部能夠訪問到全局定義的變量,但是不能修改全局定義的變量(當(dāng)然有方法可以修改)

下面我們來(lái)看看下面實(shí)例:

x = 1

deffunx():

x= 10

print(x) #打印出10

funx()print(x) #打印出1

如果局部沒有定義變量x,那么函數(shù)內(nèi)部會(huì)從內(nèi)往外開始查找x,如果沒有找到,就會(huì)報(bào)錯(cuò)

x = 1

deffunx():print(x)

funx()print(x) #打印出1

x = 1

deffunx():deffunc1():print(x)

func1()

funx()print(x) #打印出1

因此,關(guān)于作用域的問題,只需要記住兩點(diǎn)就行:

全局變量能夠被文件任何地方引用,但修改只能在全局進(jìn)行操作;如果局部沒有找到所需的變量,就會(huì)往外進(jìn)行查找,沒有找到就會(huì)報(bào)錯(cuò)。

二.高級(jí)函數(shù)

我們知道,函數(shù)名其實(shí)就是指向一段內(nèi)存空間的地址,既然是地址,那么我們可以利用這種特性來(lái)。

a函數(shù)名可以作為一個(gè)值

defdelete(ps):importos

filename= ps[-1]

delelemetns= ps[1]

with open(filename, encoding='utf-8') as f_read,\

open('tmp.txt', 'w', encoding='utf-8') as f_write:for line in iter(f_read.readline, ''):if line != '\n': #處理非空行

if delelemetns inline:

line= line.replace(delelemetns,'')

f_write.write(line)

os.remove(filename)

os.rename('tmp.txt',filename)defadd(ps):

filename= ps[-1]

addelemetns= ps[1]

with open(filename,'a', encoding='utf-8') as fp:

fp.write("\n", addelemetns)defmodify(ps):importos

filename= ps[-1]

modify_elemetns= ps[1]

with open(filename, encoding='utf-8') as f_read, \

open('tmp.txt', 'w', encoding='utf-8') as f_write:for line in iter(f_read.readline, ''):if line != '\n': #處理非空行

if modify_elemetns inline:

line= line.replace(modify_elemetns, '')

f_write.write(line)

os.remove(filename)

os.rename('tmp.txt', filename)defsearch(cmd):

filename= cmd[-1]

pattern= cmd[1]

with open(filename,'r', encoding="utf-8") as f:for line inf:if pattern inline:print(line, end="")else:print("沒有找到")

dic_func={'delete': delete, 'add': add, 'modify': modify, 'search': search}whileTrue:

inp= input("請(qǐng)輸入您要進(jìn)行的操作:").strip()if notinp:continuecmd_1=inp.split()

cmd=cmd_1[0]if cmd indic_func:

dic_func[cmd](cmd_1)else:print("Error")

將函數(shù)作為字典值,實(shí)現(xiàn)文本數(shù)據(jù)的增刪查改操作

b.函數(shù)名可以作為返回值

defouter():definner():pass

returninner

s=outer()print(s)######輸出結(jié)果為#######

.inner at 0x000000D22D8AB8C8>

c.函數(shù)名可以作為一個(gè)參數(shù)

defindex():print("index func")defouter(index):

s=index

s()

outer(index)######輸出結(jié)果#########

index func

所以滿足上面兩個(gè)條件中的一個(gè),都可以稱為高級(jí)函數(shù).

三.閉包函數(shù)

閉包函數(shù)必須滿足兩個(gè)條件:1.函數(shù)內(nèi)部定義的函數(shù) 2.包含對(duì)外部作用域而非全局作用域的引用

下面通過一些實(shí)例來(lái)說(shuō)明閉包函數(shù):

實(shí)例一:以下僅僅在函數(shù)內(nèi)部定義了一個(gè)函數(shù),但并非閉包函數(shù).

defouter():definner():print("inner func excuted")

inner()#調(diào)用執(zhí)行inner()函數(shù)

print("outer func excuted")

outer()#調(diào)用執(zhí)行outer函數(shù)

####輸出結(jié)果為##########

inner func excuted

outer func excuted

實(shí)例二:以下在函數(shù)內(nèi)部定義了一個(gè)函數(shù),而且還引用了一個(gè)外部變量x,那么這個(gè)是閉包函數(shù)么?答案:不是

x = 1

defouter():definner():print("x=%s" %x) #引用了一個(gè)非inner函數(shù)內(nèi)部的變量

print("inner func excuted")

inner()#執(zhí)行inner函數(shù)

print("outer func excuted")

outer()#####輸出結(jié)果########

x=1inner func excuted

outer func excuted

在回頭來(lái)看看對(duì)閉包函數(shù)的定義,是不是兩條都滿足?聰明的你,一定發(fā)現(xiàn)不滿足第二條.對(duì),這里的變量x,是屬于全局變量,而非外部作用于域的變量。再來(lái)看看下面例子:

defouter():

x= 1

definner():print("x=%s" %x)print("inner func excuted")

inner()print("outer func excuted")

outer()#####輸出結(jié)果#########

x=1inner func excuted

outer func excuted

顯然,上面實(shí)例滿足閉包函數(shù)的條件。現(xiàn)在,你應(yīng)該清楚,作為一個(gè)閉包函數(shù),必須得滿足上述的兩個(gè)條件,缺一不可。但是,一般情況下,我們都會(huì)給閉包函數(shù)返回一個(gè)值.這里先不說(shuō)為什么.在接下來(lái)的內(nèi)容中,你會(huì)看到這個(gè)返回值的用途.

defouter():

x= 1

definner():print("x=%s" %x)print("inner func excuted")print("outer func excuted")return inner #返回內(nèi)部函數(shù)名

outer()

現(xiàn)在我們來(lái)抽象的定義一下閉包函數(shù)。它是函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。在實(shí)現(xiàn)深約束時(shí),需要?jiǎng)?chuàng)建一個(gè)能顯式表示引用環(huán)境的東西,并將它與相關(guān)的子程序捆綁在一起,這樣捆綁起成為閉包。在上面實(shí)例中,我們可以發(fā)現(xiàn),閉包函數(shù),它必須包含自己的函數(shù)以及一個(gè)外部變量才能真正稱得上是一個(gè)閉包函數(shù)。如果沒有一個(gè)外部變量與其綁定,那么這個(gè)函數(shù)不能算得上是閉包函數(shù)。

那么怎么知道一個(gè)閉包函數(shù)有多少個(gè)外部引用變量呢?看看下面代碼.

defouter():

x= 1y= 2

definner():print("x= %s" %x)print("y= %s" %y)print(inner.__closure__)returninner

outer()######輸出結(jié)果#######

(, )

結(jié)果表明,在inner內(nèi)部,引用了兩個(gè)外部局部變量。如果引用的是非局部變量,那么這里輸出的為None.

閉包函數(shù)的特點(diǎn):1.自帶作用域 2.延遲計(jì)算

那么閉包函數(shù)有什么作用呢?我們清楚的知道,閉包函數(shù)在定義時(shí),一定會(huì)綁定一個(gè)外部環(huán)境。這個(gè)整體才能算的上是一個(gè)閉包函數(shù),那么我們可以利用這個(gè)綁定特性,來(lái)完成某些特殊的功能。

實(shí)例三:根據(jù)傳入的URL,來(lái)下載頁(yè)面源碼

from urllib.request importurlopendefindex(url)defget()returnurlopen(url).read()returnget

python= index("http://www.python.org") #返回的是get函數(shù)的地址

print(python()) #執(zhí)行g(shù)et函數(shù)《并且將返回的結(jié)果打印出來(lái)

baidu = index("http://www.baidu.com")print(baidu())

有人可以會(huì)說(shuō),這個(gè)不滿足閉包函數(shù)的條件啊!我沒有引用非全局的外部變量啊。其實(shí)并非如此,給,我們之前說(shuō)過,只要在函數(shù)內(nèi)部的變量都屬于函數(shù)。那么我在index(url),這個(gè)url也屬于函數(shù)內(nèi)部,只不過我們省略一步而已,所以上面那個(gè)函數(shù)也是閉包函數(shù)。

四.裝飾器

有了以上基礎(chǔ),對(duì)于裝飾器就好理解了.

裝飾器:外部函數(shù)傳入被裝飾函數(shù)名,內(nèi)部函數(shù)返回裝飾函數(shù)名。

特點(diǎn):1.不修改被裝飾函數(shù)的調(diào)用方式 2.不修改被裝飾函數(shù)的源代碼

a.無(wú)參裝飾器

有如下實(shí)例,我們需要計(jì)算一下代碼執(zhí)行的時(shí)間。

importtime, randomdefindex():

time.sleep(random.randrange(1, 5))print("welcome to index page")

根據(jù)裝飾器的特點(diǎn),我們不能對(duì)index()進(jìn)行任何修改,而且調(diào)用方式也不能變。這時(shí)候,我們就可以使用裝飾器來(lái)完成如上功能.

importtime, randomdef outer(func): #將index的地址傳遞給func

definner():

start_time=time.time()

func()#fun = index 即func保存了外部index函數(shù)的地址

end_time =time.time()print("運(yùn)行時(shí)間為%s"%(end_time -start_time))return inner #返回inner的地址

defindex():

time.sleep(random.randrange(1, 5))print("welcome to index page")

index= outer(index) #這里返回的是inner的地址,并重新賦值給index

index()

裝飾器實(shí)現(xiàn)計(jì)時(shí)

但是,有些情況,被裝飾的函數(shù)需要傳遞參數(shù)進(jìn)去,有些函數(shù)又不需要參數(shù),那么如何來(lái)處理這種變參數(shù)函數(shù)呢?下面來(lái)看看有參數(shù)裝飾器的使用情況.

b.有參裝飾器

def outer(func): #將index的地址傳遞給func

def inner(*args, **kwargs):

start_time=time.time()

func(*args, **kwargs) #fun = index 即func保存了外部index函數(shù)的地址

end_time =time.time()print("運(yùn)行時(shí)間為%s"%(end_time -start_time))return inner #返回inner的地址

下面來(lái)說(shuō)說(shuō)一些其他情況的實(shí)例。

如果被裝飾的函數(shù)有返回值

deftimmer(func):def wrapper(*args,**kwargs):

start_time=time.time()

res=func(*args,**kwargs) #res來(lái)接收home函數(shù)的返回值

stop_time=time.time()print('run time is %s' %(stop_time-start_time))returnresreturnwrapperdefhome(name):

time.sleep(random.randrange(1,3))print('welecome to %s HOME page' %name)return 123123123123123123123123123123123123123123

這里補(bǔ)充一點(diǎn),加入我們要執(zhí)行被裝飾后的函數(shù),那么應(yīng)該是如下調(diào)用方式:

home = timmer(home) # 等式右邊返回的是wrapper的內(nèi)存地址,再將其賦值給home,這里的home不在是原來(lái)的的那個(gè)函數(shù),而是被裝飾以后的函數(shù)了。

像home = timmer(home)這樣的寫法,python給我們提供了一個(gè)便捷的方式------語(yǔ)法糖@.

以后我們?cè)僖诒谎b飾的函數(shù)之前寫上@timmer,它的效果就和home = timmer(home)是一樣的。

如果一個(gè)函數(shù)被多個(gè)裝飾器裝飾,那么執(zhí)行順序是怎樣的。

importtimeimportrandomdeftimmer(func):defwrapper():

start_time=time.time()

func()

stop_time=time.time()print('run time is %s' %(stop_time-start_time))returnwrapperdefauth(func):defdeco():

name=input('name:')

password=input('password:')if name == 'egon' and password == '123':print('login successful')

func()#wrapper()

else:print('login err')returndeco

@auth#index = auth(timmer(index))

@timmer #index = timmer(index)

defindex():

time.sleep(3)print('welecome to index page')

index()

View Code

實(shí)驗(yàn)結(jié)果表明,多個(gè)裝飾器裝飾一個(gè)函數(shù),其執(zhí)行順序是從下往上。

關(guān)于裝飾器,還有一些高級(jí)用法,有興趣的可以自己研究研究。

c.類裝飾器

裝飾器不僅可以是函數(shù),還可以是類,相比函數(shù)裝飾器,類裝飾器具有靈活度大、高內(nèi)聚、封裝性等優(yōu)點(diǎn)。使用類裝飾器主要依靠類的__call__方法,當(dāng)使用 @ 形式將裝飾器附加到函數(shù)上時(shí),就會(huì)調(diào)用此方法。

classFoo(object):def __init__(self, func):

self._func=funcdef __call__(self):print('class decorator runing')

self._func()print('class decorator ending')

@Foo  # bar = Foo(bar)defbar():print('bar')

bar()  # Foo(bar)()#結(jié)果#class decorator runing#bar#class decorator ending

classFoo(object):def __init__(self):pass

def __call__(self, func):def _call(*args, **kw):print('class decorator runing')return func(*args, **kw)return_callclassBar(object):

@Foo()def bar(self, test, ids): #bar = Foo()(bar)

print('bar')

Bar().bar('aa', 'ids')

總結(jié)

以上是生活随笔為你收集整理的python装饰器作用和功能_python装饰器大详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。