2.3.3裝飾器與語(yǔ)法糖

總目錄:http://www.itdecent.cn/p/e406a9bc93a9

Python - 子目錄:http://www.itdecent.cn/p/50b432cb9460

裝飾器三前提:作用域、高階函數(shù),閉包

作用域

?L_E_G_B

a = 10? ?

def f():

? ? a=5? ?

? ? def inner():

? ? ? ? a = 7

? ? ? ? print(a)

? ? ? ? return 1

7


高階函數(shù)

1.函數(shù)名可以作為參數(shù)輸入

2.也可以作為返回值


閉包

def outer():

? ? x = 10

? ? def inner():? ? ? #條件1:?inner就是內(nèi)部變量

? ? ? ? print(x)? ? ? ? #條件2:外部環(huán)境的一個(gè)變量

? ? return inner? ? ?#結(jié)論:內(nèi)部函數(shù)inner是一個(gè)閉包

f=outer()

f()

10


裝飾器

裝飾器本質(zhì)上是一個(gè)Python函數(shù),它可以讓其他函數(shù)在不需要做任何代碼變動(dòng)的前提下增加額外功能,裝飾器的返回值也是一個(gè)函數(shù)對(duì)象。它經(jīng)常用于有切面需求的場(chǎng)景,比如:插入日志、性能測(cè)試、事務(wù)處理、緩存、權(quán)限校驗(yàn)等場(chǎng)景。裝飾器是解決這類問(wèn)題的絕佳設(shè)計(jì),有了裝飾器,我們就可以抽離出大量與函數(shù)功能本身無(wú)關(guān)的雷同代碼并繼續(xù)重用。

現(xiàn)在我們來(lái)舉一個(gè)例子:

假設(shè)要寫一個(gè)銀行存款取款的程序,那么主干程序肯定要實(shí)現(xiàn)存款功能和取款功能:

def a():

? ? print("存款中……")

def b():

? ? print("取款中……")

button=1

if button ==1:

? ? a()

else:

? ? b()

但是除了存款功能和取款功能外,需要添加密碼驗(yàn)證功能,那么菜雞程序員肯定會(huì)添加一個(gè)新的函數(shù):

def a():

? ? print("存款中……")

def b():

? ? print("取款中……")

def c():

? ? print("密碼驗(yàn)證中……")

button=1

if button ==1:

? ? c()

? ? a()

else:

? ? c()

? ? b()

或者:

def a():

? ? c()

? ? print("存款中……")

def b():

? ? c()

? ? print("取款中……")

def c():

? ? print("密碼驗(yàn)證中……")

button=1

if button ==1:

? ? a()

else:

? ? b()

但是這兩種寫法冗余程度高,都違背了開(kāi)放封閉原則,這只是兩個(gè)功能就要每一步都要做出修改,那么上百個(gè)功能呢?

那么我們?cè)诓桓淖冊(cè)瘮?shù)的情況下進(jìn)行修改:

def a():

? ? print("存款中……")

def b():

? ? print("取款中……")

def c(fun):

? ? print("密碼驗(yàn)證中……")

? ? fun()

button=1

if button ==1:

? ? c(a)

else:

? ? c(b)

這樣修改確實(shí)沒(méi)有修改原代碼,但是程序邏輯已經(jīng)改變,如果功能多的話,都要一一修改,可維護(hù)性差。

這樣,就需要我們使用裝飾器了,在不影響原程序,原邏輯,不違背開(kāi)放封閉原則的情況下:

def c(func):

? ? def inner():

? ? ? ? print("密碼驗(yàn)證中……")

? ? ? ? func()

? ? return inner


def a():

? ? print("存款中……")


def b():

? ? print("取款中……")

button=1

if button ==1:

? ? a1=c(a)

? ? a1()

else:

? ? b1=c(b)

? ? b1()

這個(gè)例子只是在說(shuō)明裝飾器的用途和標(biāo)準(zhǔn)用法。

帶參裝飾器

現(xiàn)在讓我們擺脫這個(gè)例子,看一下帶參數(shù)的裝飾器,

def c(func):

? ? def inner():

? ? ? ? print("woshi")

? ? ? ? func()

? ? return inner


def my(a):

? ? print(a)


my1=c(my("xiaobai"))

my1()

運(yùn)行這個(gè)代碼,會(huì)報(bào)錯(cuò),原因是裝飾器的返回值是inner,而my等同于inner。

現(xiàn)在我們修改一下

def c(func):

? ? def inner(*a,**b):

? ? ? ? print("woshi")

? ? ? ? func(*a,**b)

? ? return inner


def my(a):

? ? print(a)

my1=c(my("xiaobai"))

my1()

現(xiàn)在我們來(lái)看一下,裝飾器中的函數(shù)返回值:

def c(func):

? ? def inner(*a,**b):

? ? ? ? print("woshi")

? ? ? ? func(*a,**b)

? ? return inner

@c

def my1(a):

? ? return a

@c

def my2(a):

? ? print(a)


re1 = my1("111")

re2 = my2("222")

print(re1,re2)

woshi

woshi

222

None None

這是打印的結(jié)果,可以看出來(lái)兩個(gè)函數(shù)的返回值均為空,是因?yàn)?,無(wú)論被裝飾的函數(shù)有無(wú)返回值,其結(jié)果都無(wú)返回值,原因其實(shí)很簡(jiǎn)單,因?yàn)閕nner()函數(shù)根本就沒(méi)有返回值。為了實(shí)現(xiàn)有返回值的函數(shù)被裝飾之后仍然有返回值,需要inner函數(shù)與被裝飾函數(shù)的返回值保持一致。

再來(lái)簡(jiǎn)單修改一下:

def c(func):

? ? def inner(*a,**b):

? ? ? ? print("woshi")

? ? ? ? re3=func(*a,**b)

? ? ? ? return re3

? ? return inner

@c

def my1(a):

? ? return a

@c

def my2(a):

? ? print(a)


re1 = my1("111")

re2 = my2("222")

print(re1,re2)

woshi

woshi

222

111 None

可以看到,有返回值的函數(shù)被裝飾之后依然有返回值,沒(méi)有返回值的函數(shù)被裝飾之后則沒(méi)有返回值,符合我們想要的結(jié)果。


語(yǔ)法糖

上面的@c便是語(yǔ)法糖。

我們來(lái)定義一個(gè)函數(shù)

def my():

? ? print("123")

然后我們要在123上加一行=和一行*

def a(func):

? ? def inner():

? ? ? ? print('='*15)

? ? ? ? func()

? ? return inner

def b(func):

? ? def inner():

? ? ? ? print('*'*15)

? ? ? ? func()

? ? return inner

@a

@b

def my():

? ? print("123")

my()

帶參語(yǔ)法糖

但是這樣的話,函數(shù)a和函數(shù)b代碼冗余,可以用帶參數(shù)的語(yǔ)法糖來(lái)優(yōu)化一下:

def a(char):

? ? def b(func):

? ? ? ? def inner():

? ? ? ? ? ? print(char*15)

? ? ? ? ? ? func()

? ? ? ? return inner

? ? return b

@a('=')

@a('*')

def my():

? ? print("123")

my()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 裝飾器本質(zhì)上是一個(gè)函數(shù),該函數(shù)用來(lái)處理其他函數(shù),它可以讓其他函數(shù)在不需要修改代碼的前提下增加額外的功能,裝飾器的返...
    胡一巴閱讀 479評(píng)論 0 0
  • 寫在前面的話 代碼中的# > 表示的是輸出結(jié)果 輸入 使用input()函數(shù) 用法 注意input函數(shù)輸出的均是字...
    FlyingLittlePG閱讀 3,227評(píng)論 0 9
  • http://blog.csdn.net/ablo_zhou/article/details/5471952 Py...
    王江濤_6000閱讀 396評(píng)論 0 1
  • 閉包和裝飾器 閉包 定義:在函數(shù)嵌套的前提下,內(nèi)部函數(shù)使用了外部函數(shù)的變量,并且外部函數(shù)返回了內(nèi)部函數(shù),我們把這個(gè)...
    一只學(xué)不會(huì)編程的汪汪閱讀 409評(píng)論 0 0
  • 一,老師問(wèn)全班同學(xué):“小明有三個(gè)兒子,大兒子叫小日,二兒子叫小月,那么他第三個(gè)兒子叫什么”?這時(shí)王小明突然站起來(lái)回...
    金字塔頂閱讀 310評(píng)論 0 2

友情鏈接更多精彩內(nèi)容