python——裝飾器相關內容

下面將依次介紹裝飾器是如何來的,裝飾器如何裝飾帶返回值的函數,如何裝飾帶參數的函數,多個裝飾器如何裝飾同一個函數以及什麼叫做帶參數裝飾器。

'''
    假設我們想要對於我們寫的函數進行計時(這個函數可以很多很多個),那麼我們如何做呢?下面是一種方法
'''
import time

def timmer(function):  # 這就是裝飾器函數
    def inner():
        start = time.time()
        function()  # 這就是被裝飾的函數
        end = time.time()
        print(end - start)
    return inner # 注意這裏是返回內部函數名,不帶括號

def func():  #
    print("Hello Python")

func = timmer(func)
func()  # 注意這裏的func()執行的其實是inner函數

# 通過上面這種方法,我們沒有修改函數的調用方式,去在原有函數的基礎上添加了一些功能,這就是裝飾器的一種粗略的模型。
'''
裝飾器原則:開放封閉原則
    封閉:對修改是封閉的(相當於禁止在函數修改任何東西,即使是添加一個變量名)
    開放:對擴展是開放的
裝飾器的作用:不想修改函數的調用方式,但是還想在原來的函數前後添加功能
'''
# 在上面的方法中,我們的func函數並沒有返回值,但是通常來說,函數都是有返回值的,上面的方法並不能讓我們獲得func()函數的返回值

def timmer(function):  # 這就是裝飾器函數
    def inner():
        start = time.time()
        function()  # 這就是被裝飾的函數
        end = time.time()
        print(end - start)
    return inner # 注意這裏是返回內部函數名,不帶括號

@timmer  # python中的語法糖 @裝飾器函數名   這裏@timmer就相當於執行了 func = timmer(func) @下面緊跟着的就是被裝飾函數
def func():  #
    print("Hello Python")
    return '你好,世界'

# func = timmer(func)
a = func()  # 注意這裏的func()執行的其實是inner函數
print(a)


#-----------------------------------------------------------------------------------------------------------
# 那麼如何得到func函數的返回值呢?其實只要在inner函數裏添加一個接收func函數返回值的變量,並將該變量返回即可

def timmer(function):  # 這就是裝飾器函數
    def inner():
        start = time.time()
        ret = function()  # 這就是被裝飾的函數
        end = time.time()
        print(end - start)
        return ret
    return inner # 注意這裏是返回內部函數名,不帶括號

@timmer  # python中的語法糖 @裝飾器函數名   這裏@timmer就相當於執行了 func = timmer(func) @下面緊跟着的就是被裝飾函數
def func():  #
    print("Hello Python")
    return '你好,世界'

# func = timmer(func)
a = func()  # 注意這裏的func()執行的其實是inner函數
print(a)
# 上面就是裝飾帶返回值函數的裝飾器
#-----------------------------------------------------------------------------------------------------------
# 下面是裝飾帶參數函數的裝飾器
def timmer(function):  # 這就是裝飾器函數
    def inner(a):
        start = time.time()
        ret = function(a)  # 這就是被裝飾的函數
        end = time.time()
        print(end - start)
        return ret
    return inner # 注意這裏是返回內部函數名,不帶括號

@timmer  # python中的語法糖 @裝飾器函數名   這裏@timmer就相當於執行了 func = timmer(func) @下面緊跟着的就是被裝飾函數
def func(a):  #
    print("Hello Python", a)
    return '你好,世界'

# func = timmer(func)
a = func(a)     # 注意這裏的func()執行的其實是inner函數
print(a)
#-----------------------------------------------------------------------------------------------------------
# 上面只是一個函數並且只有一個參數,那麼如果有兩個函數,並且是關鍵字傳參等,那麼上面這種形式就不行了,下面是這種方法的應對形式
def timmer(function):  # 這就是裝飾器函數
    def inner(*args, **kwargs):
        start = time.time()
        ret = function(*args, **kwargs)  # 這就是被裝飾的函數
        end = time.time()
        print(end - start)
        return ret
    return inner # 注意這裏是返回內部函數名,不帶括號

@timmer  # python中的語法糖 @裝飾器函數名   這裏@timmer就相當於執行了 func = timmer(func) @下面緊跟着的就是被裝飾函數
def func(a):
    print("Hello Python", a)
    return '你好,世界'

@timmer
def func1(a, b):
    print("Hello Python", a, b)
    return '你好'

# func = timmer(func)
a = func(1)     # 注意這裏的func()執行的其實是inner函數
b = func1(1, 2)
print(a)
print(b)

#=======================================================================================================================#
'''
上面就是裝飾器的形成過程,下面是裝飾器的固定形式
'''
def wrapper(function):  # 這就是裝飾器函數,function是被裝飾的函數
    def inner(*args, **kwargs):
        '''這裏寫被裝飾函數之前要做的事'''
        ret = function(*args, **kwargs)  # 這就是被裝飾的函數
        '''這裏寫被裝飾函數之後要做的事'''
        return ret
    return inner # 注意這裏是返回內部函數名,不帶括號

@wrapper  # 等價於 func = wrapper(func)
def func(a):
    '''這是一個func函數'''
    print("Hello Python", a)
    return '你好,世界'

print(func.__name__) # __name__打印函數名,這裏打印的是inner,因爲經過裝飾器裝飾後func引用的函數已經不再是原函數了
print(func.__doc__) # 打印文檔註釋

#=======================================================================================================================#
# 對於被裝飾函數,我們不想改變其引用的函數,即我們原本的func函數在被裝飾後應該依然是func函數名指的依然是原本的函數,而不是inner函數,那麼我們應該怎麼做呢?
# 很簡單,我們只需要給inner函數使用wraps裝飾器裝飾一下即可
from functools import wraps

def wrapper(function):  # 這就是裝飾器函數,function是被裝飾的函數
    @wraps(function)  # 帶參數的裝飾器
    def inner(*args, **kwargs):
        '''這裏寫被裝飾函數之前要做的事'''
        ret = function(*args, **kwargs)  # 這就是被裝飾的函數
        '''這裏寫被裝飾函數之後要做的事'''
        return ret
    return inner # 注意這裏是返回內部函數名,不帶括號

@wrapper
def func(a):
    '''這是一個func函數'''
    print("Hello Python", a)
    return '你好,世界'

print(func(1))
print(func.__name__) # __name__打印函數名,這裏打印的就是原先的func了
print(func.__doc__) # 打印 這是一個func函數

#=======================================================================================================================#
# 對於多個裝飾器裝飾一個函數時

def wrapper1(function):
    print("裝飾器1")
    def inner(*args, **kwargs):
        print("inner1")
        return function(*args, **kwargs)
    return inner

def wrapper2(function):
    print("裝飾器2")
    def inner(*args, **kwargs):
        print("inner2")
        return function
    return inner

@wrapper1
@wrapper2
def func():
    print("func函數")
func()
# 打印的結果是: 當多個裝飾器裝飾一個函數時,執行時的順序是:最先裝飾的裝飾器,最後一個執行。它遵循了先進後出這樣一個規則
# 裝飾器2
# 裝飾器1
# inner1
# inner2

#=======================================================================================================================#
# 帶參數的裝飾器(即三層裝飾器)
FLAG = True  # 設置全局變量,控制裝飾器是否工作
def wrapper_out(flag):
    def wrapper(function):
        def inner(*args, **kwargs):
            if flag: # 當flag爲True 即全局的FLAG爲True時才運行裝飾器擴展的功能
                '''這裏寫裝飾器擴展的功能'''
                print("裝飾器工作區域")
                rec = function(*args, **kwargs)
                return rec
            else:
                return function(*args, **kwargs)
        return inner
    return wrapper

@wrapper_out(FLAG) # 這裏先運行 wrapper_out(FLAG) 相當於先調用了wrapper_out函數,在@ 即 先wrapper = wrapper_out(FLAG) 再 func = wrapper(func)
def func():
    return "你好,python"

@wrapper_out(FLAG)
def func2():
    return "你好,java"

print(func())
print(func2())
 

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