第九章:装饰器

装饰器简介

装饰器形成的过程:最简单的装饰器——有返回值的——有一个参数——万能参数
装饰器的作用:不想修改函数的调用方式,但是还想在原来的函数前后添加功能
原则:开放封闭原则
开放:对扩展是开放的
封闭:对修改是封闭的
语法糖:@装饰器函数名
本质:并不是一门新的技术 而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的结果

装饰器的固定模式

无参数装饰器

import time


def wrapper(f):  # 装饰器函数,f是被装饰的函数
    # 定义一个内置函数,且和下面统级别的返回值名字一致且不加括号
    # 动态参数一定要原封不动的传给 被装饰的函数 f()
    def inner(*args, **kwargs):
        '''在被装饰函数之前要做的事'''
        ret = f(*args, **kwargs)  # 被装饰的函数  函数执行完的返回值要原封不动传给 return
        '''在被装饰函数之后要做的事'''
        return ret

    return inner


@wrapper  # 语法糖 @装饰器函数名 等价于 func = wrapper(func)
def func(a, b):  # 被装饰的函数
    time.sleep(0.01)
    print('你好:世界', a, b)
    return '新年好'


# print(func(23,45))  # 接收返回值
ret = func(23, 45)  # 接收返回值
print(ret)

有参数装饰器

def outer_plus(mode):
    def outer(func):
        def inner(*args, **kwargs):
            res = func(*args, **kwargs)
            return res
        return inner
    return outer


@outer_plus('MySQL')	# outer_plus('MySQL') 表示 outer_plus('MySQL') == outer
def func():				# @ 表示 @outer 即:func == outer(func) == inner
    pass

多层语法糖

def wrapper(func):
    def inner(*args,**kwargs):
        print("-----1-----")
        ret = func(*args,**kwargs)
        print("*****1*****")
        return ret
    return inner

def wrapper2(func):
    def inner2(*args,**kwargs):
        print("-----2-----")
        ret = func(*args,**kwargs)
        print("*****2*****")
        return ret
    return inner2

def wrapper3(func):
    def inner3(*args,**kwargs):
        print("-----3-----")
        ret = func(*args,**kwargs)
        print("*****3*****")
        return ret
    return inner3

@wrapper3
@wrapper2
@wrapper
def f():
    print("in f")
    return '就是这样'
print(f())
输出结果如下:
-----3-----
-----2-----
-----1-----
in f
*****1*****
*****2*****
*****3*****
就是这样

装饰器修复技术

from functools import wraps


def outer(func_name):
    @wraps(func_name)  # 仅仅是为了让装饰器的效果更加逼真 平时可以不写
    def inner(*args, **kwargs):
        """我是inner 我擅长让人蒙蔽"""
        res = func_name(*args, **kwargs)
        return res
    return inner

@outer
def func():
    """我是真正的func 我很强大 我很牛 我很聪明"""
    pass


# help(func)  # func() 我是真正的func 我很强大 我很牛 我很聪明
# print(func)   # <function func at 0x0585A2B8>
func()

作业

1.编写一个用户认证装饰器
  函数:register login transfer withdraw 
  基本要求
   	 执行每个函数的时候必须先校验身份 eg: jason 123
  拔高练习(有点难度)
   	 执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
  提示:全局变量 记录当前用户是否认证
2.利用递归函数依次打印列表中每一个数据值
	l1 = [1,[2,[3,[4,[5,[6,[7,[8,]]]]]]]]
3.利用有参装饰器编写多种用户登录校验策略

解答

# 执行每个函数的时候必须先校验身份 eg: ysg 123
flag = False

# 定义登录装饰器
def login(func):
    def inner(*args, **kwargs):
        global flag
        # 被装饰函数之前要做的事
        # 校验登录操作为装饰前要做的事
        if flag:
            ret = func(*args, **kwargs)
            # 被装饰函数之后要做的事
            return ret
        else:
            name = input('请输入用户名>>>').strip()
            pwad = input('请输入密码>>>').strip()
            if name == 'ysg' and pwad == '123':
                flag = True
                ret = func(*args, **kwargs)
                # 被装饰函数之后要做的事
                return ret
            else:
                print('用户校验失败')
    return inner

@login  # transfer = login(transfer)
def transfer():
    print('进行转账')

@login
def withdraw():
    print('进行取款')

transfer()
withdraw()
# 2.利用递归函数依次打印列表中每一个数据值
lit = [1, [2, [3, [4, [5, [6, [7, [8, ]]]]]]]]
new_lit = []


def list_open(lit):
    for i in lit:
        if isinstance(i, list):
            list_open(i)
        else:
            new_lit.append(i)


list_open(lit)
print(new_lit)
# 3.利用有参装饰器编写多种用户登录校验策略
def val_out(val):
    def outer(func):
        def inner(*args, **kwargs):
            if val == 'only_one':
                name = input('输入用户名>>>').strip()
                pawd = input('输入密码>>>').strip()
                if name == 'ysg' and pawd == '123':
                    ret = func(*args, **kwargs)
                    return ret
                else:
                    print('用户名或密码错误')
            elif val == 'data_list':
                lit = ['jason|123','kevin|321','tony|222']
                dit = {i.split('|')[0]:i.split('|')[1] for i in lit}
                name = input('输入用户名>>>').strip()
                pawd = input('输入密码>>>').strip()
                if name in dit and pawd == dit.get(name):
                    ret = func(*args, **kwargs)
                    return ret
                else:
                    print('用户名或密码错误')
            elif val == 'data_file':
                with open(r'F:\user.txt', 'r', encoding='utf-8') as fr:
                    dit = {i.split('|')[0]:i.split('|')[1] for i in fr.read().splitlines()}
                name = input('输入用户名>>>').strip()
                pawd = input('输入密码>>>').strip()
                if name in dit and pawd == dit.get(name):
                    ret = func(*args, **kwargs)
                    return ret
                else:
                    print('用户名或密码错误')
        return inner
    return outer


@val_out('only_one')
def only_one():
    print('直接写死的  ysg 123')

@val_out('data_list')
def data_list():
    print("数据来源于列表 ['jason|123','kevin|321','tony|222']")

@val_out('data_file')
def data_file():
    print('数据来源于文件 jason|123  tom|321')


only_one()
data_list()
data_file()
posted @ 2022-10-12 08:16  亦双弓  阅读(399)  评论(0)    收藏  举报