Python基礎知識:5:裝飾器,python基礎知識裝飾

來源:互聯網
上載者:User

Python基礎知識:5:裝飾器,python基礎知識裝飾

    裝飾器的作用就是為已經存在的對象添加額外的功能。

    基於開放封閉原則,在不改變調用者的前提下,在調用之前或之後增加一些功能;

    當你有100個或更多的調用程式需要同時增加/修改同一個內容時,使用裝飾器會非常有用;


案例1:假設100個程式都要同時額外增加一個功能,如在執行程式前列印字元log;

    一種實現方式是:把這個功能複製到100個程式中,但缺點是無法靈活控制outer和f的先後執行順序,且修改起來很麻煩,需要一個程式一個程式的去修改。

    這時,就需要一個裝飾器來封裝一個功能。

#定義裝飾器
def outer():#定義在常規程式外的函數outer,作用是列印log
   print('log')
#使用裝飾器
def f1():
outer()#使用裝飾器
  print('F1')
def f2():
outer()
print('F2')
def f100():
outer()
print('F100')
#執行程式
print('f1執行效果:')
f1()
print('f2執行效果:')
f2()
print('f100執行效果:')
f100()

執行結果:

要理解裝飾器,必須要先理解函數,具體可參考另外篇博文。

函數兩個基本知識:

1)函數的執行從上往下,後一個變數/函數會覆蓋前一個變數/參數。

def f1():
print(123)

def f1():
print(456)
f1()

#因為執行順序為從上到下,因此後一個f1會覆蓋前一個f1,執行結果為456


函數的執行順序案例:

2)函數是可以作為整體進行傳遞的;如果傳遞的為函數名,而又沒有加(),則函數是作為整體去傳遞

#先將f1作為整體傳遞給f2的xxx,再執行f2中的函數體,因為f2的函數體xxx(),因此,繼續執行f1()
def f1():
print("函數1執行",123)

def f2(xxx):
print("函數2執行",456)
xxx()#會去執行f1()
f2(f1)#將f1傳遞給xxx,則xxx=f1

執行結果:


裝飾器@+函數名,有兩大功能:

1)自動執行outer函數,且將其下面裝飾的函數名f1當做參數傳遞給裝飾器中的參數;

2)將outer函數的傳回值重新賦值給f1


案例2:解釋裝飾器的工作原理:在裝飾器中無其他的函數

案例2-1:無裝飾器案例:執行f1()

1)儲存傳回值

def f1():
print('F1')
return 123#f1有傳回值123
f1() #執行f1函數體,執行結果為F1

執行結果:

2)不儲存傳回值

def f1():
print('F1')
return 123#f1有傳回值123
r=f1() #執行f1函數體,並將f1的傳回值賦值給r
print(r)#因f1的函數體有傳回值,為123,直接列印123

執行結果:


案例2-2:加入裝飾器後:執行f1(),會修改原有的f1函數體,而原有的函數體不再被執行

案例解讀:

  • 函數從上到下執行,在執行def f1()時,發現其上面的裝飾器,會把裝飾器下的f1作為參數傳遞給裝飾器,代替裝飾器中的參數func;

  • f1的函數體,將不會被執行,比如:print('F1')就不會出現

  • 裝飾器執行後的傳回值111,重新賦值給f1,因此f1目前的值為111

  • 執行f1(),就是執行111(),就會出錯

1)因為裝飾器的傳回值為111,而執行f1即執行111(),這個就會出錯了
def outer(func):
return "111"
@outer#裝飾器
def f1():
print('F1')
return "123"#f1有傳回值123
f1()#因f1已經被重新賦值了111,執行f1()即執行111(),因此再執行是就會出錯

執行結果:出錯的執行結果

2)可以看下f1此時的值;執行結果為111
def outer(func):
return "111"
@outer#裝飾器
def f1():
print('F1')
return "123"#f1有傳回值123
print(f1)#因f1已經被重新賦值111


案例3:解釋裝飾器的工作原理:裝飾器中內建函數,暫無參數func

案例3-1:裝飾器下的函數會傳遞給裝飾器的參數

    案例解讀:執行裝飾器,把f1賦值給func,定義inner函數;裝飾器的傳回值為inner函數,賦值給f1,此時再執行f1()時,即為執行inner(),結果為"列印inner函數"

#裝飾器中有函數
def outer(func):#func為老的f1
   def inner():#定義inner,下面inner的函數體
       print("執行inner函數體")
return inner #inner代指inner函數的函數體,並將這個函數體賦值為f1

@outer
def f1():
print('執行f1函數體')
return "123"#f1有傳回值123
f1()#f1已被重新賦值為inner,因此當執行f1()時,即執行inner()

執行結果:


案例4:解釋裝飾器的工作原理:裝飾器中內建函數,且有參數func。

因f1會被替換成裝飾器的傳回值,因此,裝飾的參數func指的老的f1,新的f1為inner,內層函數無傳回值的情況

1)先列印字元log,再執行程式

def outer(func):#func為原有的f1
   def inner(): #定義inner函數
        print('inner函數:log')
func()#因func代指原來的f1,因此執行原有的f1函數體
   return inner#此為裝飾器的傳回值,被賦值為f1

@outer
def f1():
print('執行f1函數體')
return "123"#f1有傳回值123
f1()#即執行裝飾器中的inner函數

執行結果:

2)先列印字元log,再執行程式,再列印after:

def outer(func):#func為原有的f1
   def inner(): #定義inner函數
       print('inner函數:log')
func()#因func代指原來的f1,因此執行原有的f1函數體
       print('after')
return inner#此為裝飾器的傳回值,被賦值為f1

@outer
def f1():
print('執行f1函數體')
return "123"#f1有傳回值123
f1()#即執行裝飾器中的inner函數

執行結果:

案例5:裝飾器內層函數有傳回值

先列印字元log,再執行程式,同時取舊程式的傳回值,再列印after:

def outer(func):#func為原有的f1
   def inner(): #定義inner函數
       print('inner函數:log')
r=func()#因func代指原來的f1,因此執行原有的f1函數體,並將舊f1的傳回值傳遞r,即r="f1的傳回值123"
       print('after')
return r #inner函數最後傳回值為人,函數遇到return,下面就不執行了
   return inner#此為裝飾器的傳回值,被賦值為f1

@outer
def f1():
print('執行f1的函數體')
return "f1的傳回值123"#f1有傳回值123
r=f1()#即執行裝飾器中的inner函數,並取inner函數的傳回值,即r
print(r)

執行結果:


此處可以總結下裝飾器的執行順序:


案例6和案例7講解內建函式有參數的情況:

案例6:裝飾器中的參數:當f1有參數時,裝飾器中也需要輸入參數

def outer(func):#func為原有的f1
   def inner(a): #定義inner函數
       print('inner函數:log')
r=func(a)#因func代指原來的f1,因此執行原有的f1函數體,並將舊f1的傳回值傳遞r,即r="f1的傳回值123"
       print('after')
return r #inner函數最後傳回值為人,函數遇到return,下面就不執行了
   return inner#此為裝飾器的傳回值,被賦值為f1

@outer
def f1(arg):
print(arg)
return "f1的傳回值123"#f1有傳回值123
r=f1("f1需要加入參數")#需要傳遞參數
print(r)

執行結果:


案例7:裝飾器中的參數:f1...f100的參數個數不一致時,需要使用動態參數

def outer(func):#func為原有的f1
   def inner(*args,**kwargs): #定義inner函數,使用動態參數
       print('inner函數:log')
r=func(*args,**kwargs)#因func代指原來的f1,因此執行原有的f1函數體,並將舊f1的傳回值傳遞r,即r="f1的傳回值123"
       print('after')
return r #inner函數最後傳回值為人,函數遇到return,下面就不執行了
   return inner#此為裝飾器的傳回值,被賦值為f1

@outer
def f1(arg):
print(arg)
return "f1的傳回值123"#f1有傳回值123
@outer
def f2(arg1,arg2):
print(arg1,arg2)
return "f2的傳回值456"#f1有傳回值123

r1=f1('f1傳遞1個參數')
print(r1)
print('--------執行傳遞倆參數案例--------')
r2=f2("f2傳遞參數1","f2傳遞參數2")
print(r2)
執行結果:


案例連結:https://pan.baidu.com/s/1dFvrRS9 密碼:27cj






著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.