python筆記3:裝飾器

Table of Contents

01介紹

02實現裝飾器

03裝飾器的作用 對有參函數的裝飾

04 裝飾多個函數

05不定長參數的函數裝飾

06 返回值函數裝飾 通用裝飾器

07多個裝飾器對同一個函數裝飾

08應用

09類裝飾器


01介紹

不會裝飾器,不能說會python喲

def foo():

       print('foo')

 

foo#函數名指向函數

foo()#執行函數

 

foo=lambda x: x+1#foo變量名被指向匿名函數

foo()#執行lambda表達式

Py把函數名、方法名、變量名都當作變量名對待,所以不能相同

只要有相同的,則用的時候就是最後定義的一個

需求:基礎平臺部門寫功能,業務部門調用(容易被裁員)

讓業務部門調用的時候加權限驗證,不加不能調用功能函數

#法1:冗餘過多

def f1():

       #權限驗證

       print('f1')

def f2():

       #權限驗證

       print('f2')

 

f1()

f2()

#法2

def check_login():

       #權限驗證

       pass

 

def f1():

       check_login()

       print('f1')

def f2():

       check_login()

       print('f2')

 

f1()

f2()

開放封閉原則規定已經實現的功能代碼不能修改(封閉),但可以擴展(開放)

裝飾器效果

def set_func(func):

       def call_func():

              print("權限驗證")

              func()

       return call_func

 

@set_func#在函數執行前加代碼

def test1():

       #set_func()#類似效果

       print("test1")

 

test1()

02實現裝飾器

裝飾器實現過程:

def set_func(func):#傳入的指針是test1

       def call_func():

              print("權限驗證")

              func()

       return call_func

 

def test1():

       print("test1")

 

ret=set_func(test1)#ret得到call_func指針

ret()#執行print("權限驗證")和調用func()即指向test1

test1=set_func(test1)#不用修改調用的函數名,重新修改指針

test1()#執行print("權限驗證")和func()即test1

@set_func可看作一種簡略寫法

@set_func#等價於test1=set_func(test1)

def test1():

       print("test1")

由於裝飾器(修飾器)的閉包實現過程是整個調用原函數,新加的功能只能在原函數調用之前或之後執行,不能在執行到一半時插入

03裝飾器的作用 對有參函數的裝飾

裝飾器能夠實現對功能的擴展,同時不改變調用的函數名

作用:如計算函數運行的時間

Import time

time.time()

1508763827.814883

整數部分是1970年到現在秒數(Unix時間戳)

import time

def set_func(func):#傳入的指針是test1

       def call_func():

              start_time=time.time()

              func()

              stop_time=time.time()

              print("all time is %f" % (stop_time - start_time))

       return call_func

 

@set_func#等價於test1=set_func(test1)

def test1():

       print("test1")

test1()#執行print("權限驗證")和func()即test1

對無參數、返回值函數最簡單

對有參數無返回值函數裝飾

def set_func(func):#傳入的指針是test1

       def call_func(a):#2.接收到100

              print("權限驗證")

              func(a)#3.100作爲實參調用test1

       return call_func

 

@set_func

def test1(num):

       print("test1:%d" % num)

 

test1(100)#1.100給了call_fun

04 裝飾多個函數

 同一個裝飾器裝飾多個函數

def set_func(func):

       def call_func(a):

              print("權限驗證")

              func(a)

       return call_func

 

@set_func

def test1(num):

       print("test1:%d" % num)

 

@set_func

def test1(num):

       print("test2:%d" % num)

 

test1(100)#1.100給了call_fun

test2(200)

兩次裝飾分別創建多個閉包

test1、test2分別指向另一個函數,該函數分別嵌套原本的func(test1、test2)

裝飾器@寫完就已經裝飾了,而不需要等調用test1()

def set_func(func):

       print("開始裝飾")

       def call_func(a):

              print("權限驗證")

              func(a)

       return call_func

 

@set_func

def test1(num):

       print("test1:%d" % num)

 

#test1(100)

test1未運行

終端打印出:開始裝飾

05不定長參數的函數裝飾

不定長參數的即便使用:

def test1(num,*args,**kwargs):

       print("test1:%d" % num)

       print("test1:", args)#作爲元組打印

       print("test1:", kwargs)#作爲元組打印

 

test1(1,2,3,mm=1)

其中mm=1爲關鍵字參數

輸出結果:

test1:1

test1:(2,3)

test1:{‘mm’:1}

使用解釋器:

def set_func(func):

       print("開始裝飾")

       def call_func(*args,**kwargs):#num1在args中以元組保存

              print("權限驗證")

              func(*args,**kwargs)#傳遞處也要帶*,*代表對元組拆包,**代表對字典拆

       return call_func

 

@set_func

def test1(num,*args,**kwargs):#*代表多餘的普通參數給args,**代表關鍵字參數給kwargs

       print("test1:%d" % num)

       print("test1:", args)

       print("test1:", kwargs)

 

test1(1,2,3,mm=1)#調用call_func

傳遞可變參數時不能寫成func(args,kwargs)否則只傳遞了一個元組一個字典

06 返回值函數裝飾 通用裝飾器

def set_func(func):

       print("開始裝飾")

       def call_func(*args,**kwargs):#num1在args中以元組保存

              print("權限驗證")

              return func(*args,**kwargs)#將接收到的返回值傳遞

       return call_func

 

@set_func

def test1(num,*args,**kwargs):#*代表多餘的普通參數給args,**代表關鍵字參數給kwargs

       print("test1:%d" % num)

       print("test1:", args)

       print("test1:", kwargs)

       return "ok"#誰調用的test1就向誰返回

 

ret=test1(1)#調用call_func

print(ret)

無返回值函數可適用:

一般接收無返回值函數,拿到的都是none

使用該裝飾器裝飾無返回值的函數,return none結果也一樣是none

多返回值可適用:

多返回值時返回元組

def set_func(func):

       print("開始裝飾")

       def call_func(*args,**kwargs):

              print("權限驗證")

              return func(*args,**kwargs)

       return call_func

 

@set_func

def test1(num,*args,**kwargs):

       print("test1:%d" % num)

       print("test1:", args)

       print("test1:", kwargs)

       return "ok","2"#多返回值時返回元組

 

ret=test1(1)#調用call_func

print(ret)

 

通用裝飾器主要有3點:

  1. call_func(*args,**kwargs)接收可變參數
  2. func(*args,**kwargs)傳遞實參時拆包
  3. return func將接收到的返回值傳遞

07多個裝飾器對同一個函數裝飾

def add_verify1(func):

       print("開始1裝飾")

       def call_func(*args,**kwargs):#num1在args中以元組保存

              print("裝飾1")

              return func(*args,**kwargs)#將接收到的返回值傳遞

       return call_func

def add_verify2(func):

       print("開始2裝飾")

       def call_func(*args,**kwargs):#num1在args中以元組保存

              print("裝飾2")

              return func(*args,**kwargs)#將接收到的返回值傳遞

       return call_func

 

@add_verify1

@add_verify2

def test1():

       print("test1")

 

test1()

輸出結果

開始2裝飾

開始1裝飾

裝飾1

裝飾2

裝飾與執行順序不同

裝飾add_verify1時,將add_verify2包括以下當成整個函數,需要先裝飾下面的,下面的就變成新閉包

@add_verify1#等價於test1=add_verify1(test1),此時的test1指向已經改變

@add_verify2#等價於test1=add_verify2(test1)

def test1():

       print("test1")

08應用

對原函數返回值加"<h1></h1>"標籤

def set_func_1(func):

       def call_func(*args,**kwargs):

              return "<h1>"+func(*args,**kwargs)+"</h1>"

       return call_func

 

@set_func_1

def get_str():

       return "haha"

 

print(get_str())

再加"<td></td>"標籤

def set_func_1(func):

       def call_func(*args,**kwargs):

              # print("裝飾1")

              return "<h1>"+func(*args,**kwargs)+"</h1>"

       return call_func

def set_func_2(func):

       def call_func(*args,**kwargs):

              # print("裝飾1")

              return "<td>"+func(*args,**kwargs)+"</td>"

       return call_func

 

@set_func_1

@set_func_2

def get_str():

       return "haha"

 

print(get_str())

輸出結果:

<h1><td>haha</td></h1>

因爲h1裝飾的在最上面,執行的時候再遞歸調用td的裝飾

09類裝飾器

用類對函數裝飾

class Test(object):

       def __init__(self,func):#帶self的可算作實例方法,但肯定不是類方法

              self.func=func#存下func引用

       def __call__(self):

              print("裝飾器功能")

              return self.func()#指向get_str

 

@Test#get_str=Test(get_str)創建Test類的實例對象

def get_str():

       return "haha"

 

print(get_str())#調用時調用的是類裝飾器的call方法

若要改成通用裝飾器:get_str()調用類的call方法,所以參數也在call接收

類方法,靜態方法可以通過類名調用,如@Test.jingtaifangfa

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章