zoukankan      html  css  js  c++  java
  • 装饰器详解

    一、nonlocal关键词

    1、作用:将local和enclosing(e中的名字需要提前定义)中的名字统一

    2、应用场景:如果想在被嵌套的函数中修改外部函数变量(名字)的值

    3、案例

    def outer():
        num = 0
        print(num)       # 结果为  0
        def inner():     # 如果想在被嵌套的函数中修改外部函数变量(名字)的值
            nonlocal num # 将L与E(E中的名字需要提前定义)的名字统一
            num = 100
            print(num)   # 结果为 100
        inner()
        print(num)       # 结果为 100
    outer()
    num =100
    def fn():
        global num
        num = 10
    def fn2():
        global num
        num = 20
    fn2()
    fn()
    print(num)

    二、开放封闭原则

    1、定义:不能修改源代码,不能更改调用方式,但可以对外提供增加新功能的特性

    2、开放:修改了源代码,没有更改调用方式,对外调用方式还是原来的,但功能有所增加,不能更改被装饰对象(函数)的调用方式,且达到了增加功能的效果

    def fn():
        print('fn run1')
        print('fn run')
        print('fn run3')
    fn()

    3、封闭:没有修改源代码,但更改了调用方式 。

    不能修改被被装饰对象(函数)的源代码

    def fn():
        print('fn run')
    fn()
    def wrap(fn):
        print('fn run1')
        fn()
        print('fn run3')
        fn()
    wrap(fn)

    三、装饰器

    1、装饰器:闭包的一个应用场景。为一个函数添加新功能的工具

    def vase():
        print('插花')
    vase()              # 结果为 插花
    
    # 增加一个绘画观赏功能:不满足封闭开放原则,修改了源代码
    def vase():
        print('插花')
        print('绘画观赏')
    vase()
    # 结果为
    # 插花
    # 绘画观赏
    
    # 增加一个绘画观赏功能,不满足开放封闭原则,更改了调用方式
    def vase():
        print('插花')
    vase()
    def wrap(vase):
        vase()
        print('绘画观赏')
    wrap(vase)
    def vase():
        print('插花')
    
    def wrap(vase):
        def fn():
            print('绘画观赏')
        return fn
    vase = wrap(vase)
    vase()
    def vase():
        print('插花')
    
    # 下方的函数嵌套结构就是装饰器*****
    def wrap(x): #x=vase
        def fn():
            x()  # 原有的vase
            print('绘画:进行观赏')
        return fn          # 拓展功能后的vase
    vase = wrap(vase)      # 将拓展功能后的功能函数重新赋值给vase
    vase()                 # 功能拓展了,且调用方式不变

    2、装饰器简化语法

    def outer(fn):
        def inner():
            fn()
            print('绘画观赏')
        return inner
    def wrap(fn):
        def inner():
            fn()
            print('摆放功能')
        return inner
    # 语法糖|笑笑语法
    @wrap            # 总结:一个函数可以被任意一个装饰器装饰,也可以被任意几个装饰器装饰
    @outer           #       装饰的顺序会影响新增功能的执行顺序
    
    def vase():
        print('插花')
    vase()
    # 结果为
    # 插花
    # 绘画观赏
    # 摆放功能

    四、有参有反的函数被装饰

    案例
    
    # 增加一个账号处理功能:3位及以上英文字符或汉字
    def check_usr(fn):
        def inner(usr, pwd):
            if not (len(usr) >= 3 and usr.isalpha()):
                print('账号验证失败')
                return False
            result = fn(usr, pwd)  # login
            return result
        return inner
    
    # 增加一个密码处理功能:6位及以上英文和数字
    def check_pwd(fn):
        def inner(usr, pwd):
            if not (len(pwd) >= 6 and pwd.isalnum()):
                print('密码验证失败')
                return False
            return fn(usr, pwd)
        return inner
    
    # 登录功能
    @check_usr  # login = check_usr(login) = inner
    @check_pwd
    def login(usr, pwd):
        if usr == 'abc' and pwd =='123qwe':
            print('登录成功')
            return True
        print('登录失败')
        return False
    
    res = login('abc', '123qwe')  # inner
    print(res)

    五、登录认证案例

    is_login = False  # 登录状态
    
    def login():
        usr = input('usr: ')
        if not (len(usr) >= 3 and usr.isalpha()):
            print('账号验证失败')
            return False
        pwd = input('pwd: ')
        if usr == 'abc' and pwd =='123qwe':
            print('登录成功')
            is_login = True
        else:
            print('登录失败')
            is_login = False
    
    
    # 完成一个登录状态校验的装饰器
    def check_login(fn):
        def inner(*args, **kwargs):
            # 查看个人主页或销售功能前:如果没有登录先登录,反之可以进入其功能
            if is_login != True:
                print('你未登录')
                login()
            # 查看个人主页或销售
            result = fn(*args, **kwargs)
            return result
        return inner
    
    # 查看个人主页功能
    @check_login
    def home():
        print('个人主页')
    
    # 销售功能
    @check_login
    def sell():
        print('可以销售')
    
    home()

    五、案例

    1、写出完整的装饰器(不用考虑带参装饰器,就是普通装饰器)语法

    def wrapper(func):
        def inner(*args, **kwargs):
            pass
            result = func(*args, **kwargs)
            pass
            return result
        return inner

    2、有一个计算两个数和的方法,为其添加一个确保两个参数都是int或float类型的装饰器,保证运算不会抛异常

    def check_num(func):
        def inner(n1, n2):
            b1 = isinstance(n1, int) or isinstance(n1, float)
            b2 = isinstance(n2, int) or isinstance(n2, float)
            if not (b1 and b2):
                print('不能求和')
                return  # 结束掉,不让其进入计算功能
            return func(n1, n2)
        return inner
    
    @check_num
    def add(n1, n2):
        return n1 + n2
    
    print(add(1, '2'))

    3、有一个一次性录入人名并返回人名的方法(人名只考虑存英文),为其添加一个装饰器,使得处理后人名首字母一定大写

    def upper_name(func):
        def inner():
            result = func()
            return result.title()  # Owen
        return inner
    
    @upper_name
    def get_name():
        name = input('name: ')  # owen
        return name
    
    print(get_name())
  • 相关阅读:
    模块化工具require 学习笔记
    学习Jade模板引擎
    通过border来实现各种三角符号
    使用vscode 编译 sass
    Javascript 运行机制
    Vue调试工具 vue-devtools
    MVVM框架
    通信类
    面向对象
    原型和原型链
  • 原文地址:https://www.cnblogs.com/zhangguosheng1121/p/10650985.html
Copyright © 2011-2022 走看看