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()