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

歡迎訪問 生活随笔!

生活随笔

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

python

python重写和装饰器_python装饰器

發(fā)布時間:2025/3/12 python 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python重写和装饰器_python装饰器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

python裝飾器的本質,就是閉包!

我們一般談Python的閉包,都是指普通的入參,而談裝飾器的時候,入參一定有函數!閉包和裝飾器,返回的都是函數。函數是代碼的最小封裝單位,裝飾器作用于函數,它不影響函數自身的執(zhí)行,只是在函數的執(zhí)行前后增加一些“裝飾性”的動作。裝飾器被稱為python的語法糖(syntax sugar),也被視為python支持AOP編程(面向切面編程)的工具。

簡單裝飾器

以下代碼實現了一個最簡單的額裝飾器,功能是給帶上裝飾器的函數,在函數執(zhí)行前,增加一行print打印,代碼如下:

test1函數加上了calling_trace裝飾器,在第7行,這一行代碼的作用,相同于第11行的注釋。test1還是test1,這個名字沒有變,只是換成了一個閉包函數的返回值,此閉包函數,就是裝飾器,它接收一個函數作為參數。以上代碼運行效果如下:

$ python3 deco.py

calling test1

test1 is runing...

我們還可以稍微復雜一點點,既然是裝飾器,被裝飾的函數執(zhí)行前后都可以加點小動作。修改后的代碼如下:

def calling_trace(func):

def wrapper():

print('calling', func.__name__)

a = func()

print('this is the reture:',a)

return wrapper

@calling_trace

def test2():

print('test2 is runing...')

return 'www.pynote.net'

# test2 = calling_trace(test2)

test2()

新的裝飾器沒有改名字,只是獲取了被裝飾函數的返回值,并將返回值打印出來。運行效果如下:

$ python3 deco.py

calling test2

test2 is runing...

this is the reture: www.pynote.net

test2函數執(zhí)行前后,都增加了一些動作,作為裝飾!

這就是裝飾器的概念:不修改已有函數的代碼,也不修改已有函數的調用處代碼,卻達到了豐富函數功能的效果!本質上裝飾器是對函數的一種封裝,只是我們要理解@語法。

閉包和裝飾器

裝飾器的本質就是閉包,我們如果把上面這段代碼重寫一遍,采用閉包的語法形式,不使用@語法,效果是完全一樣的:

def calling_trace(func):

def wrapper():

print('calling', func.__name__)

a = func()

print('this is the reture:',a)

return wrapper

def test2():

print('test2 is runing...')

return 'www.pynote.net'

t = calling_trace(test2)

t()

以上代碼,沒有@語法的使用啦,用變量t來獲取calling_trace返回的函數對象,然后調用,效果與使用裝飾器完全一樣:

$ python3 deco.py

calling test2

test2 is runing...

this is the reture: www.pynote.net

使用@語法,閱讀代碼就如吃糖!

裝飾帶參數的函數

如果被裝飾的函數有參數,需要在裝飾器內部原樣復制函數的參數定義。請看示例:

def calling_trace(func):

def wrapper(a,b,c=3):

print('calling', func.__name__)

a = func(a,b,c)

print('reture value:',a)

return wrapper

@calling_trace

def test3(a,b,c=3):

print('test3 is runing...')

return a+b+c

test3(1,2,5)

test3(1,2)

裝飾器返回的函數的參數定義,要與被裝飾函數的參數定義保持一致!以上代碼運行結果如下:

$ python3 deco.py

calling test3

test3 is runing...

reture value: 8

calling test3

test3 is runing...

reture value: 6

就算裝飾參數個數不定的函數,語法上也是一樣的,請看下面代碼,test4函數的參數個數不定:

def calling_trace(func):

def wrapper(*args):

print('calling', func.__name__)

a = func(*args)

print('reture value:',a)

return wrapper

@calling_trace

def test4(*args):

print('test4 is runing...')

return sum(args)

test4(1,2,3,4,5,6,7,8)

test4(23,34,45,56)

*args表示一個tuple,在函數定義處出現,就是packing打包調用時的參數,在調用時出現,就是unpacking展開tuple。跟**kw(對應dict)用法一樣。以上代碼運行效果:

$ python3 deco.py

calling test4

test4 is runing...

reture value: 36

calling test4

test4 is runing...

reture value: 158

給帶參數的函數加裝飾器,還有一種更通用更常見的參數寫法,這種寫法在修改函數參數和調用處時,有可以反過來保持裝飾器部分代碼不變。示例如下:

def calling_trace(func):

def wrapper(*args, **kw):

print('calling', func.__name__)

a = func(*args, **kw)

print('reture value:',a)

return wrapper

@calling_trace

def test5(a,b,c=3):

print('test5 is runing...')

return a+b+c

test5(1,2)

test5(1,2,c=8)

裝飾器中使用*args和**kw來接收和傳遞參數!這個地方要好好體會,這是python的一個特別精妙的地方。以上代碼運行結果如下:

$ python3 deco.py

calling test5

test5 is runing...

reture value: 6

calling test5

test5 is runing...

reture value: 11

帶參數的裝飾器

本文以上示例,都是不帶參數的裝飾器,在使用@語法的時候,沒有參數。而裝飾器本身也可以帶參數,通過在裝飾器外再使用閉包,給裝飾器封裝其執(zhí)行環(huán)境,可以使裝飾器的功能更強大更靈活,也可以更好的控制函數的執(zhí)行(比如在某些情況下不執(zhí)行)。而帶參數的裝飾器,在語法上,也就跟閉包區(qū)分開來。(應該就是這個原因,閉包和裝飾器在python中是分成了兩個概念)

def calling_trace(run):

def deco(func):

def wrapper(*args, **kw):

print('calling', func.__name__)

if run == 1:

a = func(*args, **kw)

print('reture value:',a)

else:

print('not allow to run')

return wrapper

return deco

# test5 = calling_trace(run=1)(test5)

@calling_trace(run=1)

def test5(a,b,c=3):

print('test5 is runing...')

return a+b+c

@calling_trace(run=0)

def test6(*args):

print('test6 is runing...')

return sum(args)

test5(1,2)

test5(1,2,c=8)

test6(23,34,45,56)

先看一下這段代碼的運行結果:

$ python3 deco.py

calling test5

test5 is runing...

reture value: 6

calling test5

test5 is runing...

reture value: 11

calling test6

not allow to run

達到預期,test5可以執(zhí)行,而test6不允許執(zhí)行。

calling_trace實際上就是一個閉包,它有一個參數,run,調用calling_trace(run=1)后,就相當于返回了一個有run這個參數的裝飾器。然后再用這個裝飾器去“修飾”它自己的參數func。這個效果,就如注釋掉的那行代碼。如果不使用@語法,把那行代碼注釋打開(放在test5的定義后面),運行效果一模一樣!

多重裝飾器

函數可以有多個裝飾器!多個裝飾器的效果,就相當于對函數進行了多層的封裝包裹,而不同的裝飾器對函數執(zhí)行的功能影響,完全獨立。比如有個裝飾器用來控制函數是否能夠被執(zhí)行,另一個裝飾器控制函數的所有raise出來的異常。

@a

@b

@c

def tt(): pass

# tt = a(b(c(tt)))

tt函數上面帶3個裝飾器,想過正如注釋掉的那行代碼。

我真的覺得python裝飾器的設計,實在是非常精妙!

-- EOF --

總結

以上是生活随笔為你收集整理的python重写和装饰器_python装饰器的全部內容,希望文章能夠幫你解決所遇到的問題。

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