裝飾器

裝飾器

定義

裝飾的工具python

必需要遵循的原則:「開放封閉」閉包

開放:對源函數功能的添加是開放的app

封閉:對源函數功能修改是封閉的函數

裝飾器的做用

在不修改被裝飾對象源代碼和調用方式的前提下,增長新功能工具

必須遵循的原則:url

一、不修改被裝飾對象的源代碼code

二、不修改被裝飾對象的調用方式對象

爲何要使用裝飾器

解決代碼冗餘問題,提升代碼可擴展性blog

怎麼使用裝飾器

編寫裝飾器經過閉包函數實現ip

裝飾器推導過程

# # 裝飾器推導過程
def move():
    '''下載電影的源函數'''
    print('開始下載')
    time.sleep(2)
    print('下載完成')
def fun(index):
    def down():
        star_time = time.time()
        index() # 將被裝飾對象move賦值給index執行
        end_time = time.time()
        print(f'總耗時{end_time - star_time}')
    return down
fun(move)()
# 有返回值時
def move():
    '''下載電影的源函數'''
    print('開始下載')
    time.sleep(2)
    print('下載完成')
    return '明日之巔.mp4'

def fun(index):
    def down():
        star_time = time.time()
        res = index()  # 將index執行結果賦值給res
        # print(res)
        end_time = time.time()
        print(f'總耗時{end_time - star_time}')
        return res  # 將index返回值返回出來
    # print(down())
    return down
move = fun(move)  # 將調用方式改爲被裝飾對象
move()
# 源函數有參數時
def move(url):
    '''下載電影的源函數'''
    print(f'{url}開始下載')
    time.sleep(2)
    print('下載完成')
    return '明日之巔.mp4'

def wrapper(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)
        end_time = time.time()
        print(f'總耗時:{end_time - start_time}')
        return res
    return inner
move = wrapper(move)
move(('https://www.cnblogs.com'))

裝飾器最終模板

def wrapper(func):
    def inner(*args, **kwargs):
        # 調用前增長新功能
        res = func(*args, **kwargs)  # 調用被裝飾對象,接收返回值
        # 調用後增長的新功能
        return res  # 接收被裝飾對象的返回值
    return inner

裝飾器語法糖

一、裝飾器的語法糖是屬於裝飾器的

二、用@+裝飾器名,在被裝飾對象開頭

三、在使用裝飾器語法糖時,裝飾器必須定義在被裝飾對象之上

# 增長統計代碼運行時間的裝飾器
def wrapper(func):
    def inner(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        end_time = time.time()
        print(end_time-start_time)
        return res
    return inner
# 使用語法糖
@wrapper
def movie():
    print("開始下載")
    time.sleep(2)
    print('下載結束')
# 不使用語法糖調用增長新功能後的函數
# movie = wrapper(movie)
# movie()
# 使用語法糖後可直接調用
movie()

疊加裝飾器

在同一個被裝飾對象中,添加多個裝飾器,並執行

每個新功能都寫一個新的裝飾器,不然會致使代碼冗餘,結構不清晰,可擴展性差

@裝飾器1
@裝飾器2
@裝飾器3
def 被裝飾對象():
	pass

注意:在調用被裝飾對象時,纔會執行添加的新功能

疊加裝飾器裝飾順序,執行順序:

裝飾的順序:由下往上裝飾

執行的順序:由上往下執行

注意:

一、裝飾器內函數inner中出現任何判斷,最後都要返回「調用後的被裝飾對象」func(*args,**kwargs)

二、被裝飾對象在調用時,若是還有其餘裝飾器,會先執行其餘裝飾器中的inner

def wrapper1(func1):
    def inner1(*args, **kwargs):
        print("1————start")
        res = func1(*args, **kwargs)
        print("1————end")
        return res
    return inner1

def wrapper2(func2):
    def inner2(*args, **kwargs):
        print("2————start")
        res = func2(*args, **kwargs)
        print("2————end")
        return res
    return inner2

def wrapper3(func3):
    def inner3(*args, **kwargs):
        print("3————start")
        res = func3(*args, **kwargs)
        print("3————end")
        return res
    return inner3

@wrapper1  
@wrapper2
@wrapper3
def index():
    print("index")
index()
>>>
# 執行順序:由上而下
# 裝飾順序:由下而上
1————start
2————start
3————start
index
3————end
2————end
1————end

有參裝飾器

無參裝飾器:裝飾在被裝飾對象時,沒有傳參數的裝飾器

# 如下是無參裝飾器
@wrapper1  
@wrapper2
@wrapper3

有參裝飾器:在某些時候咱們須要給用戶的權限進行分類

# 如下是有參裝飾器
@wrapper1(參數1)  
@wrapper2(參數2)  
@wrapper3(參數3)

若是咱們想提供多種不一樣的認證方式以供選擇 , 函數inner須要一個driver參數,而函數wrapper與inner的參數都有其特定的功能,不能用來接受其餘類別的參數,能夠在wrapper的外部再包一層函數user_auth,用來專門接受額外的參數,這樣便保證了在user_auth函數內不管多少層均可以引用到

# 給用戶的權限進行分類
def user_auth(driver):
    def wrapper(func):
        def inner(*args, **kwargs):
            if driver == "svip":
                # 加入超級會員的功能
                res = func(*args, **kwargs)
                return res
            elif driver == "vip":
                # 加入會員的功能
                res = func(*args, **kwargs)
                return res
            else:
                # 加入普通用戶的功能
                res = func(*args, **kwargs)
                return res
        return inner
    return wrapper

@user_auth(driver='svip')
def user_power():
    pass

user_power()

wraps

是一個修復工具,修復的是被裝飾對象的空間

使用:

一、先從functools中調用wraps >>> from functools import wraps

二、裝飾器在定義內層函數前加@wraps(func) 修更名稱空間:將inner >>> func

三、inner前加@wraps(func)是將inner名稱空間修改到func,若是不用@wraps(func)打印註釋本質打印的是inner的註釋,加上@wraps(func)修復被裝飾對象的空間,打印註釋就會打印被裝飾對象的註釋

# 函數對象.__doc__   是查看內部的註釋
from functools import wraps
# 從functools中調用wraps模塊
def wrapper(func):
    @wraps(func)  # 修更名稱空間,inner >>>  func
    def inner(*args,**kwargs):
        '''
        裝飾器的註釋
        '''
        # 調用被裝飾對象前加的功能
        res = func(*args,**kwargs)
        # 調用被裝飾對象前加的功能
        return res
    return inner

@wrapper
def index():
    '''
    被裝飾對象index的註釋
    :return:
    '''
    pass
print(index.__doc__)
# 加上@wraps(func)
>>>
    被裝飾對象index的註釋
    :return:
# 不加@wraps(func)
>>>

        裝飾器的註釋
相關文章
相關標籤/搜索