python基础 day14 装饰器

一、装饰器的认识

  • 在不改变原被装饰的函数的源代码以及调用方式情况下,为其添加新的功能。
  • 完全遵循开放封闭原则
  • 装饰器的本质就是闭包
# 标准版装饰器
def wrapper(f):  # f 是传入的被装饰的函数名
    def inner(*args, **kwargs):  # 传入被装饰的函数的参数
        '''添加额外功能,执行被装饰函数之前的操作'''
        ret = f(*args, **kwargs)  # 执行被装饰的函数,并获取被装饰函数的返回值
        '''添加额外功能,执行被装饰函数之后的操作'''
        return ret
    return inner

@wrapper
def func():
    pass

func()
  • 装饰器实现功能的分析

1.我们给这个测试函数加一个装饰器,计算执行这个函数需要的时间

# step1:
import time
def test_func():  # 这是需要被装饰的函数
    time.sleep(1)
    print('this is a test function')

# 我们给这个测试函数加一个装饰器,计算执行这个函数需要的时间
def wrapper(f):
    start_time = time.time()
    f()
    end_time = time.time()
    print(end_time - start_time)

wrapper(test_func)

# 但是装饰器要符合开放封闭原则,并且被装饰函数的调用方式也改变了

2.使用闭包,实现开放封闭原则

# step2:
import time
def test_func():  # 这是需要被装饰的函数
    time.sleep(1)
    print('this is a test function')

# 使用闭包,实现开放封闭原则
def wrapper(f):
    # f = wrapper(test_func)  # f就是一个闭包中的自由变量
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print(end_time - start_time)
    return inner
# wrapper(test_func)()  # 想要执行被装饰函数,就要执行inner(),而wrapper(test_func)返回的就是inner
test_func = wrapper(test_func)  # 使用赋值,让函数执行方式不改变
test_func()  # 实际上就是执行inner()

3.python 进行了优化,这里可以这样写

# step3:
import time
# 使用闭包,实现开放封闭原则
def wrapper(f):
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print(end_time - start_time)
    return inner

@wrapper  # 相当于test_func = wrapper(test_func)
def test_func():  # 这是需要被装饰的函数
    time.sleep(1)
    print('this is a test function')

test_func()  # 实际上就是执行inner()

4.当被装饰函数有返回值时,要在inner函数中返回被装饰函数的返回值

# step4:被装饰函数有返回值时,要在inner函数中返回被装饰函数的返回值
import time
# 使用闭包,实现开放封闭原则
def wrapper(f):
    # f = test_func
    def inner():
        start_time = time.time()
        ret = f()
        end_time = time.time()
        print(end_time - start_time)
        return ret
    return inner

@wrapper  # 相当于test_func = wrapper(test_func)
def test_func():  # 这是需要被装饰的函数
    time.sleep(1)
    print('this is a test function')
    return 'aloha'

result = test_func()  # 实际上就是执行inner()
print(result)

5.当被装饰函数需要传入参数时,要在inner函数中传入对应的参数

# step5:被装饰函数需要传入参数时,要在inner函数中传入对应的参数

import time
# 使用闭包,实现开放封闭原则
def wrapper(f):
    # f = test_func
    def inner(*args, **kwargs):
        start_time = time.time()
        ret = f(*args, **kwargs)
        end_time = time.time()
        print(end_time - start_time)
        return ret
    return inner

@wrapper  # 相当于test_func = wrapper(test_func)
def test_func(name, age):  # 这是需要被装饰的函数
    time.sleep(1)
    print('this is a test function')
    info = f'我叫{name}, 今年{age}'
    return 'aloha', info

result = test_func('jason', 18)  # 实际上就是执行inner()
print(result)

二、装饰器的应用

登录认证系统

# 简单模拟博客园登录系统
# 在访问文章,照片,文件之前,需要登录账号密码
login_status = {'username': '', 'status': False}


def get_user_password():  # 获取账号密码文件
    user_dic = dict()
    with open('user.txt', 'r', encoding='utf-8') as f1:
        for line in f1:
            line_list = line.strip().split('|')
            user_dic.update({line_list[0]: line_list[1]})
    return user_dic


def login():  # 用户登录(三次机会)
    user_dic = get_user_password()
    count = 0
    while count < 3:
        username = input("请输入账户名:").strip()
        password = input("请输入密码:").strip()
        if username in user_dic and user_dic[username] == password:
            print(f'{username}你好,欢迎登录博客园')
            login_status['username'] = username
            login_status['status'] = True
            break
        else:
            print('账号或密码错误')
        count += 1


def auth(f):  # 登录认证的装饰器
    def inner(*args, **kwargs):
        if login_status['status']:
            ret = f(*args, **kwargs)
            return ret
        else:
            login()
            ret = f(*args, **kwargs)
            return ret
    return inner


@auth
def article():
    print('欢迎访问文章页面')


@auth
def photo():
    print('欢迎访问照片页面')


@auth
def file():
    print('欢迎访问文件页面')


article()
photo()
file()
原文地址:https://www.cnblogs.com/west-yang/p/12634862.html