1. 程式人生 > 其它 >python之裝飾器

python之裝飾器

內容概要

  • 裝飾器簡介
  • 簡易裝飾器
  • 裝飾器之解決引數問題
  • 裝飾器之解決返回值問題
  • 裝飾器固定模板
  • 裝飾器語法糖
  • 裝飾器修復技術
  • 有參裝飾器

內容詳細

裝飾器簡介

器:類似工具
裝飾:為函式新增新的小功能

核心概念:在不改變被裝飾物件"原有程式碼"和"呼叫方式"的前提下,給裝飾物件新增新功能

簡易裝飾器

import time

# 被裝飾物件
def index():
    time.sleep(3)
    print('from index')
# 計算時間裝飾器
def outer(func):
    def inner():
        start_time = time.time()
	    func()  # 呼叫傳入的index函式
        end_time = time.time()
        use_time = end_time - start_time
        print(use_time)

    return inner


index = outer(index)  # 把函式名index傳入outer函式
index()  # 此時的index函式實質上是 inner函式

裝飾器之解決引數問題

# 裝飾需要傳入引數的函式
def home(username):
    print('from home')

 # 計算時間裝飾器
def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
	    func(*args, **kwargs)  # 呼叫傳入的home函式, 此時需要接收home函式傳入的引數,否則會報錯
        end_time = time.time()
        print(end_time - start_time)

    return inner

home = outer(home)
home('elijah')  # 呼叫時需要傳入相應的引數
'''
不同的被裝飾物件有時是不需要傳入引數的,有時卻需要傳入多個各種形式的引數,裝飾器就需要不停地修改
為了解決這個問題,可以使用可變長引數,用於接收位置引數和關鍵字引數

裝飾器之解決返回值問題

# 裝飾需要傳入引數的函式
def home(username):
    print('from home')
    return 'nice'

 # 計算時間裝飾器
def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
	    res = func(*args, **kwargs)  # 呼叫傳入的home函式, 此時需要接收home函式返回的值並返回出inner函式
        end_time = time.time()
        print(end_time - start_time)
        return res  # 把home函式的返回值返回出去

    return inner

home = outer(home)
home('elijah')  # 呼叫時需要傳入相應的引數

裝飾器固定模板

# 裝飾器
def outer(func):
    def inner(*args, **kwargs):
        print('執行函式之前新增的函式')
        res = func(*args, **kwargs)  # 執行被裝飾的函式
        print('執行函式之後要新增的函式')
        return res  # 將被裝飾函式執行後的返回值返回
    return inner

裝飾器語法糖

# 裝飾器語法糖
def outer(func):
    def inner(*args, **kwargs):
        print('執行函式之前新增的函式')
        res = func(*args, **kwargs)  # 執行被裝飾的函式
        print('執行函式之後要新增的函式')
        return res  # 將被裝飾函式執行後的返回值返回
    return inner

@outer  # index = outer(index)
def index():
    print('from index')

@outer  # home = outer(home)
def home():
    print('from home')

'''
裝飾器語法糖書寫規範:
	語法糖須緊貼在被裝飾物件的上方
裝飾器語法糖內部原理:
	會自動將下面緊貼著的被裝飾物件的名字當作引數傳給裝飾器函式呼叫
'''

雙層語法糖

# 雙層語法糖
# 統計函式執行時間
import time


def get_time(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)  # 執行被裝飾的函式
        end_time = time.time()
        print('函式執行時間:%s' % (end_time - start_time))
        return res  # 將被裝飾函式執行之後的返回值返回

    return wrapper


# 校驗使用者登入裝飾
def login_auth(func):
    def inner(*args, **kwargs):
        # 1.先獲取使用者的使用者名稱和密碼
        username = input('username>>>:').strip()
        password = input('password>>>:').strip()
        # 2.校驗使用者名稱和密碼是否正確
        if username == 'elijah' and password == '123':
            res = func(*args, **kwargs)  # 執行被裝飾的函式
            return res  # 將被裝飾函式執行之後的返回值返回
        print('使用者名稱或密碼錯誤 無許可權執行')

    return inner


@login_auth  # index = login_auth(wrapper)          第二步
@get_time  # get_time(index) --> 返回wrapper的函式名   第一步
def index():
    time.sleep(1)
    print('from index')


index()

裝飾器修復技術

def outer(func):
    def inner(*args, **kwargs):
        print('執行函式之前新增的函式')
        res = func(*args, **kwargs)  # 執行被裝飾的函式
        print('執行函式之後要新增的函式')
        return res  # 將被裝飾函式執行後的返回值返回
    return inner

@outer  # index = outer(index)
def index():
    print('from index')

print(index)
help(index)
# 被裝飾物件在通過 print(函式名) 和 help(函式名) 之後還是會被看出來函式的本質
from functools import wraps
def outer(func):
    @wraps(func)  # 修復技術就是為了讓被裝飾物件更加不容易被察覺裝飾了,記住要在括號內填入傳入的函式引數
    def inner(*args, **kwargs):
        print('執行函式之前新增的函式')
        res = func(*args, **kwargs)  # 執行被裝飾的函式
        print('執行函式之後要新增的函式')
        return res  # 將被裝飾函式執行後的返回值返回

    return inner


@outer  # index = outer(index)
def index():
    print('from index')

print(index)
help(index)

有參裝飾器

def outer(source_data):
    # source_data = 'file'
    def login_auth(func):
        def auth(*args,**kwargs):
            # 2.校驗使用者名稱和密碼是否正確
            # 資料的校驗方式可以切換多種
            if source_data == 'file':
                # 從檔案中獲取使用者資料並比對
                print('file檔案獲取')
            elif source_data == 'MySQL':
                # 從MySQL資料庫中獲取資料比對
                print('MySQL資料庫獲取')
            elif source_data == 'postgreSQL':
                # 從postgreSQL資料庫中獲取資料對比
                print('postgreSQL資料庫獲取')
            else:
                print('使用者名稱或密碼錯誤 無法執行函式')
        return auth
    return login_auth

@outer('file')  # 返回auth函式名,同時把index函式名傳入auth函式中
def index():
    print('from index')
@outer('MySQL')
def home():
    print('from home')

index()
home()