首页 > 其他分享 >装饰器

装饰器

时间:2023-12-13 10:24:29浏览次数:22  
标签:return args func kwargs balance 装饰 def

装饰器

  • 装饰器的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能
  • 装饰器经常用于有切面需求的场景
    • 插入日志、性能测试、事务处理、缓存、权限校验等应用场景
    • 有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用

【一】装饰器的作用

  • 软件的设计应该遵循开放封闭原则,即对扩展是开放的,而对修改是封闭的。
    • 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
    • 对修改封闭,意味着对象一旦设计完成,就可以独立完成其工作,而不要对其进行修改。
  • 软件包含的所有功能的源代码以及调用方式,都应该避免修改,否则一旦改错,则极有可能产生连锁反应,最终导致程序崩溃
    • 而对于上线后的软件,新需求或者变化又层出不穷,我们必须为程序提供扩展的可能性,这就用到了装饰器。

【二】装饰器的分类

  • 函数装饰器分为:无参装饰器和有参装饰器
  • 二者的实现原理一样,都是函数嵌套+闭包+函数对象的组合使用的产物

【三】无参装饰器

login_user_dict = {'username': 'heart', 'is_admin': True}
user_data_dict = {'heart': {'password': '123', 'role': 'admin'},
                  'god': {'password': '321', 'role': 'normal'}}

def login(username, password):
    if password == user_data_dict[username].get('password'):
        print(f'登录成功!')
        login_user_dict['username'] = username
    if user_data_dict[username].get('role') == 'admin':
        login_user_dict['is_admin'] = True
    else:
        login_user_dict['is_admin'] = False


def check_admin(func):
    def inner():
        # 验证我当前是否登录并且是管理员
        if login_user_dict['username'] and login_user_dict['is_admin']:
            # 如果是管理员,就正常执行传进来的函数地址
            res = func()
            return res
        # 重新校验
        else:
            # 重新登陆的逻辑
            return False, '重新登录'
    return inner

@check_admin
def get_money():
    # 取钱的前提是 :我已经登录过并且是管理员 ---> 验证我的登录和我的身份
    return True, '取了一万块'
print(get_money())

(1)无参装饰器模板

def outer(func):
    def inner(*args,**kwargs):
        # 这里写调用 func函数之前的逻辑
        res = func(*args,**kwargs)
        # 这里写调用 func函数之后的逻辑
        return res

    return inner
@outer
def add(*args,**kwargs):
    return 1
print(add())

(2)看电影练习

# 看电影
# 用户信息字典 --- 定义用户名 和 年龄
# 大于 18 岁 看电影
# 小于 18 岁  18禁

user_data = {'heart': 20}

def outer(func):
    def inner(*args,**kwargs):
            if user_data['heart']>=18:
                res=func()
                return res
            else:
                return False,'18禁!'
    return inner

def watch(*args,**kwargs):
    return True,'看电影!'

watch=outer(watch)
print(watch())


@outer # 语法糖格式
def watch(*args,**kwargs):
    return True,'看电影!'
print(watch())

【四】有参装饰器

  • 本质上就是在无参装饰器外面再套一层函数,再判断他的tag条件
  • 下面是取钱函数示例
user_data = {'username': 'heart', 'password': '123'}
bank_data = {'heart': {'pay_pwd': '1234', 'balance': 1000}}


def uuu(tag=None, tag_func=None):
    if tag == 'login':
        def outer(func):
            def inner(*args, **kwargs):
                username = input('请输入用户名:>>>').strip()
                password = input('请输入密码:>>>').strip()
                if username != user_data['username'] or password != user_data['password']:
                    return False, '用户名或密码错误!'
                else:
                    return func(username=username, password=password, *args, **kwargs)

            return inner

        return outer
    elif tag == 'check':
        def check_balance(func):
            def inner(*args, **kwargs):
                balance = input('请输入金额:>>>').strip()
                if not balance.isdigit():
                    return False, '非法'
                if tag_func == 'add':
                    pay_password = input('请输入密码:>>>').strip()
                    if pay_password != bank_data['heart']['pay_pwd']:
                        return False, '密码错误'
                    balance = int(balance)
                else:
                    pay_password = input('请输入密码:>>>').strip()
                    if pay_password != bank_data['heart']['pay_pwd']:
                        return False, '密码错误'
                    if not balance.isdigit():
                        return False, '非法'
                    balance = int(balance)
                    if balance > bank_data['heart']['balance']:
                        return False, '余额不足'
                return func(balance=balance, pay_password=pay_password, *args, **kwargs)

            return inner

        return check_balance


# 先验证登录
# 再验证 输入的金额 --- 符合数字 / 余额充足

# 取款函数里面
@uuu(tag='login')
@uuu(tag='check', tag_func='')
def get_balance_jian(*args, **kwargs):
    res = bank_data['heart']['balance'] - kwargs.get('balance')
    bank_data['heart']['balance'] = res
    print(bank_data)
    return f"{kwargs.get('username')}提取金额:{kwargs.get('balance')},目前余额:{res}"

    # 校验登录
    # 校验金额  符合数字 / 余额充足 --- 把金额通过装饰器 返回来
    # 拿着你的金额进行提款


@uuu(tag='login')
@uuu(tag='check', tag_func='add')
def get_balance(*args, **kwargs):
    res = bank_data['heart']['balance'] + kwargs.get('balance')
    bank_data['heart']['balance'] = res
    print(bank_data)
    return f"{kwargs.get('username')}存款金额:{kwargs.get('balance')},目前余额:{res}"

func_aa = '''
1.取钱
2.存钱
3.退出
'''

while 1:
    print(func_aa)
    uname = input('请选择功能:>>>')
    if uname == '1':
        a = get_balance_jian()
    if uname == '2':
        a = get_balance()
        print(a)
    if uname == '3':
        print('欢迎下次使用!')
        break

【五】伪装装饰器

  • 把函数内的注释伪装起来
from functools import wraps
def wrapper(func):
    def inner(*args, **kwargs):
        '''
        # 这是验证登录的装饰器
            --- 确认账号是 heart 密码是 123 才是超级管理员
        '''
        return func(*args, **kwargs)

    return inner

@wrapper
def add():
    ...

print(help(add))
print(f'----------------------------')

def wrapper(func):
    @wraps(func)
    def inner(*args, **kwargs):
        '''
        :param args: 可变长位置参数
        :param kwargs: 可变长关键字参数
        :return:
        '''
        return func(*args, **kwargs)

    return inner

@wrapper
def add():
    ...


print(help(add))

【六】语法糖

(1)多层语法糖嵌套

  • 首先定义好装饰器功能,将需要添加功能的函数体代码放置在装饰器下方,将需要执行功能的装饰器语法糖按照执行的顺序放在原函数体函数名上方,多层语法糖加载顺序由下往上,函数内执行顺序是按语法糖顺序从上往下
def outter1(func1):
    print('加载了outter1')
    def wrapper1(*args, **kwargs):
        print('执行了wrapper1')
        res1 = func1(*args, **kwargs)
        return res1
    return wrapper1

def outter2(func2):
    print('加载了outter2')
    def wrapper2(*args, **kwargs):
        print('执行了wrapper2')
        res2 = func2(*args, **kwargs)
        return res2
    return wrapper2

def outter3(func3):
    print('加载了outter3')
    def wrapper3(*args, **kwargs):
        print('执行了wrapper3')
        res3 = func3(*args, **kwargs)
        return res3
    return wrapper3


@outter1
@outter2
@outter3
def index():
    print('from index')
print(index())

## 加载了outter3
# 加载了outter2
# 加载了outter1
# 执行了wrapper1
# 执行了wrapper2
# 执行了wrapper3
# from index

标签:return,args,func,kwargs,balance,装饰,def
From: https://www.cnblogs.com/ssrheart/p/17898450.html

相关文章

  • 装饰器
    装饰器装饰器的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能装饰器经常用于有切面需求的场景插入日志、性能测试、事务处理、缓存、权限校验等应用场景有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用【一】装饰......
  • [-007-]-Python3+Unittest+Selenium Web UI自动化测试之@property装饰器默认值设置
    看示例:#!/usr/bin/python3#coding:utf-8__author__='csjin'#定义@property装饰器classPPTListModels(object):def__init__(self):self._tab_name="PPT模板"@propertydefhandle(self):returnself.__handle......
  • 【python基础之装饰器】---装饰器
    title:【python基础之装饰器】---装饰器date:2023-12-1118:54:06updated:2023-12-1214:30:00description:cover:https://home.cnblogs.com/u/dream-ze/【一】什么是装饰器装饰代指为被装饰对象添加新的功能,器代指器具/工具,装饰器与被装饰的对象均可......
  • 七、Harmony OS 之状态装饰器
    @State:@State装饰器的变量拥有其所属组件的状态,可以作为其子组件单向和双向同步的数据源。当其数值改变时,会引起相关组件的渲染刷新。@Prop:@Prop装饰的变量可以和父组件建立单向同步关系,@Prop装饰的变量二hi可变的,但修改不会同步回父组件。@Link:@Link装饰的变量和父组件构建双向......
  • 23种设计模式——装饰者模式
    今天给大家说一下23种设计模式中装饰者模式。一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。这个时候,我们就需要用到装饰者模式了,它可以实现在不增加很多子类的情况下扩展类的功能。概念:装饰者模式(DecoratorPatt......
  • 装饰器
    【一】函数的四种定义方式无参无返回值的函数defindex():res=1+1print(res)index()#2有参无返回值的函数defindex(x):print(x)index(1)#1有参有返回值defindex(x):returnxres=index(1)print(res)#1多个参数多个返回值......
  • 装饰器
    装饰器【一】什么是装饰器装饰代指为被装饰对象添加新的功能代指器具/工具,装饰器与被装饰的对象均可以是任意可调用对象。概括地讲,装饰器的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。装饰器经常用于有切面需求的场景插入日志、性能......
  • 装饰器
    今日习题*函数的四种定义方式*函数的调用方式*函数的参数类型*函数的形参类型都有哪些*函数实参传参都能如何传参*名称空间是什么,有哪些*作用域是什么,都有哪些*什么是闭包函数#【一】函数的四种定义方式#【1】无参无返回值的函数defindex():res=1+1prin......
  • NestJS 筑基:TypeScript 类和装饰器
    前言先回顾下前文中介绍了哪些内容:使用@nestjs/cli创建和管理Nest应用Hello,World示例代码分析Nest基本概念:模块,控制器,服务常用的装饰器:@Module、@Controller、@Get、@InjectableNest目录结构分析@nest/cli脚手架的命令本文先不继续讲解Nest中的内容,而是打算介绍TypeSc......
  • Python - 【装饰器】详解
    一.概念Python装饰器本质上是一个函数,用于修改其他函数的功能。装饰器可以在不改变函数代码的情况下添加新的功能,使代码更具可读性、可维护性和可重用性。使用装饰器可以把一个函数传递给另一个函数,使其具有新的行为,而无需修改函数本身的代码。二.基本语法@decorator_namedeff......