python中裝飾器的調用及帶參數的裝飾器

1 裝飾器的定義

1.把一個函數當作參數,返回一個替代版的函數,本質上就是一個返回函數的函數
2.可以在不改變原函數的基礎上,給函數增加功能。

示例:增加原函數的功能
在這裏插入圖片描述
在這裏插入圖片描述


def decorate(fun):
    def wrapper(*args,**kwargs):
        print('Welcome to 2020')
        fun()
    return wrapper
    
@decorate
def fun():
    print('Hello python!')
    
fun()

在這裏插入圖片描述
注意:decorate是用於返回wrapper(不帶()表示返回函數,帶()表示返回運行結果)


2 裝飾器的調用方式

示例:計算函數f1的運行時間

import time

def decorator(fun):
    def wrapper():
        print(time.time())
        fun()
    return wrapper
    
def f1():
    print('This is a function')
    
f = decorator(f1)##調用函數
f()

在這裏插入圖片描述


import time

def decorator(fun):
    def wrapper():
        print(time.time())
        fun()
    return wrapper
    
@decorator ###調用裝飾器(寫在原函數前面)

def f1():
    print('This is a function')
    
f1()

在這裏插入圖片描述


3 處理的原函數中有參數

注意:會先運行裝飾器,再運行原函數
示例:計算函數f1的運行時間

def decorator(func):
    def wrapper(*args):
        print(time.time())
        func(*args)
    return wrapper
    
@decorator

def f1(ser_name):
    print('This is a service: ' + ser_name)
    
f1('http')

在這裏插入圖片描述


裝飾器中也可以接受多個參數
示例:計算函數f2的運行時間

import time

def decorator(func):
    def wrapper(*args):
        print(time.time())
        func(*args)
    return wrapper
    
@decorator

def f2(ser_name1,ser_name2):
    print('This is a service: ' + ser_name1)
    print('This is a service: ' + ser_name2)
    
f2('http','ftp')

在這裏插入圖片描述


4 處理的原函數中有關鍵字參數

示例:計算函數f3的運行時間

import time

def decorator(func):
    def wrapper(*args,**kwargs):
        print(time.time())
        func(*args,**kwargs)
    return wrapper
    
@decorator

def f3(ser_name1,ser_name2,**kwargs):
    print('This is a service: ' + ser_name1)
    print('This is a service: ' + ser_name2)
    print(kwargs)
    
f3('samba','nfs',a=1,b=[1,2,3],c='test')

在這裏插入圖片描述
在這裏插入圖片描述


5 處理的原函數中有返回值

注意:處理的原函數中有返回值時,需要在裝飾器中對函數的運行結果處理(用一個變量保存函數 ,返回返回值)
示例:裝飾器實現函數計時器

def fun_list(n):
    return [2 * i for i in range(n)]
    
def fun_map(n):
    return list(map(lambda x:x*2,range(n)))
import time

def timetest(fun):
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = fun(*args,**kwargs)
        end_time = time.time()
        print('Running time is %.6f' %(end_time - start_time))
        return res
    return wrapper
    
@timetest
def fun_list(n):
    return [2 * i for i in range(n)]
@timetest
def fun_map(n):
    return list(map(lambda x:x*2,range(n)))
    
print(fun_list(10000))
print(fun_map(10000))

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述


6.保留被裝飾函數的函數名和信息文檔

import time
import functools

def timetest(fun):
    """This is a decorator fun"""
    @functools.wraps(fun)
    def wrapper(*args,**kwargs):
        """This is a wrapper function"""
        start_time = time.time()
        res = fun(*args,**kwargs)
        end_time = time.time()
        print('Running time is: %.6f' %(end_time - start_time))
        return res
    return wrapper
    
@timetest
def fun_list(n):
    """This is the fun_list function"""
    return [2 * i for i in range(n)]
@timetest
def fun_map(n):
    """This is the fun_map function"""
    return list(map(lambda x:x*2,range(n)))
    
print(fun_list.__doc__)
print(fun_list.__name__)

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述


7.帶參數的裝飾器

可以在裝飾器外面再次封裝,接收裝飾器的參數

編寫裝飾器required_types, 條件如下:
1). 當裝飾器爲@required_types(int,float)確保函數接收到的每一>個參數都是int或者float類型;
 2). 當裝飾器爲@required_types(list)確保函數接收到的每一個參數
都是list類型;
3). 當裝飾器爲@required_types(str,int)確保函數接收到的每一個>參數都是str或者int類型;
4). 如果參數不滿足條件, 打印 TypeError:參數必須爲xxxx類型

```python
import functools

def required_types(*kind):
    def required(fun):
        @functools.wraps(fun)
        def wrapper(*args,**kwargs):
            for i in args:
                if not isinstance(i,kind):
                    print('TypeError:參數必須爲%s,%s類型' %kind)
                    exit()
            else:
                res = fun(*args,**kwargs)
                return res
        return wrapper
    return required
    
@required_types(float,float)
def add(a,b):
    return a+b
    
print(add(1.0,2))

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述


8.多個裝飾器

def decorator_a(fun):
    def inner_a(*args,**kwargs):
        print('This is decorator a')
        return fun(*args,**kwargs)
    return inner_a
    
def decorator_b(fun):
    def inner_b(*args,**kwargs):
        print('This is decorator b')
        return fun(*args,**kwargs)
    return inner_b
    
@decorator_b
@decorator_a
def f(x):
    print('This is testfunc')
    return x*2
    
print(f(1))

在這裏插入圖片描述
在這裏插入圖片描述


9.裝飾器的練習

練習:創建裝飾器,打印被裝飾的函數日誌信息

創建裝飾器, 要求如下:
1. 創建add_log裝飾器, 被裝飾的函數打印日誌信息;
2. 日誌格式爲: [字符串時間] 函數名: xxx, 運行時間:xxx, 運行返回
值結果:xxx
import time
import  functools

def add_log(fun):
    @functools.wraps(fun)
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = fun(*args,**kwargs)
        end_time = time.time()
        print('[%s] 函數名: %s,運行時間: %.6f,運行返回值結果: %d'
              %(time.ctime(),fun.__name__,end_time-start_time,res))
        return res
    return wrapper

@add_log
def add(x,y):
    time.sleep(1)
    return x+y
    
add(1,10)

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述


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