zoukankan      html  css  js  c++  java
  • 装饰器理解这篇博客看完你就懂了

    1. 定义(如何理解装饰器):装饰器本生是闭包函数的一种应用,是指在不改变原函数的情况下为原函数添加新的功能的一个函数。它把被装饰的函数作为外层函数的参数传入装饰器,通过闭包操作后返回一个替代版函数。
    2. 遵循的原则: 开放封闭原则------在不改变调用方式和源代码的情况下,增加新功能。
      1. 不能改变被修饰对象(函数(后面还会对类进行装饰))的源代码(封闭)
      2. 不能改变被修饰对象(函数(以后还会对类进行装饰))的调用方式,且能达到增加功能的效果。(开放)
    3. 优点:
      1. 丰富了原函数的功能
      2. 提高了程序的可拓展性
    4. 装饰器的简单实现:
    # 无参装饰器公式:
    def fn():
        print('原功能')
        
    def outer(fn):
        def inner():
            print('新功能1')
            fn()
            print('新功能2')
        return inner
    fn = outer(fn1)
    print(fn())
    """
    案例分析: 定义一个打印插花的函数,为其前面添加绘画功能,后面添加观赏功能。
    如何一步一步完成完整的装饰器函数。
    """
    
    def vase():
        print('插花')
        
        
    def wrap():
        tag = vase  # 此时的vase 是在wrap()还没有运行结束的时候,wrap没有返回值,所以tag被赋值的是vase原先的值。
        
        def outer():
            print('绘画')
            tag()  # 原先的vase
            print('观赏')
        
        return outer  # wrap()函数返回的是outer函数的地址空间
    
    
    vase = wrap()  # vase = outer
    
    vase()

     上述代码,存在一个缺陷,就是没有写活,没办法将装饰器用在其他函数上,对于无参装饰器的正确的姿势应该如下:

    def vase():
        print('插花')    
    
    def wrap(fn):
        def outer():
            print('绘画')
            fn()  # 原先的vase
            print('观赏')
        
        return outer
    
    
    vase = wrap(vase)  # vase = outer()
    
    vase()

    那么如何让代码更简洁? python 提供一种语法糖,可以让代码看起来更简洁

    def wrap(fn):
        def outer():
            print('绘画')
            fn()  # 原先的vase
            print('观赏')
        
        return outer
    
    @wrap  # 此语法糖形式,实际上就是完成了 vase = wrap(vase)操作 = outer
    def vase():
        print('插花')
    
    
    print(vase())

    下面来看看如何进行多层装饰:(多层装饰注意一个顺序问题,执行时是从上向下执行,返回操作的时候是一层一层跳出)

    def wrap1(fn):
        def outer():
            print('绘画')
            fn()  # 原先的vase
            print('观赏')
        
        return outer
    
    
    def wrap2(fn):
        def outer():
            print('购买')
            fn()  # 原先的vase
        
        return outer
    
    @wrap2
    @wrap1
    def vase():
        print('插花')
    
    
    vase()
    
    # 购买
    # 绘画
    # 插花
    # 观赏
    
    
    @wrap1
    @wrap2
    def vase():
        print('插花')
    
    
    vase()
    
    # 绘画
    # 购买
    # 插花
    # 观赏

      5.有参有返的装饰器

    def wrap(func):
        def inner(*args, **kwargs):  # 此处 *args  (接收所有位置参数) 接收(a,b,c)以元组形式存储,kwargs  (接收所有关键字参数) 则是接收{x:4,y:5,z:6}存成字典形式
            print('新功能1')
            res = func(*args, **kwargs)
            print('新功能2')
            return res
    
        return inner
    
    
    @wrap
    def fn(a, b, c, *, x, y, z):
        print(a, b, c, x, y, z)
    
    
    re = fn(1, 2, 3, x=4, y=5, z=6)
    print(re)
    
    # 新功能1
    # 1 2 3 4 5 6
    # 新功能2
    # None   返回值是None 因为函数fn本身无return

     案例:在原登录功能下增加账号验证和密码验证功能

    # 增加一个账号安全处理功能:3位英文字母或汉字
    def check_pwd(fn):
        def inner(usr, pwd):
            if not (len(pwd) >= 6 and usr.isalpha()):
                print('账号认证失败')
                return False
            return fn(usr, pwd)
        
        return inner
    
    
    # 增加一个密码处理功能 : 6位以上英文和数字组合
    
    def check_usr(fn):  # login = check_usr(login) = inner
        def inner(usr, pwd):
            if not (len(usr) >= 3 and usr.isalnum()):
                print('密码认证失败')
                return False
            return fn(usr, pwd)
        
        return inner
    
    
    @check_usr  # login = inner   # 语法糖 谁现在下面谁先装功能,套在最外面(上面的)的是最先执行的
    @check_pwd
    # 登录功能
    def login(usr, pwd):
        if usr == 'qwe' and pwd == '123123':
            print('登录成功')
            return True
        print('登录失败')
        return False
    
    res1 = login('asdd', '123')
    res2 = login('as', '123123')
    res3 = login('qwe', '123')
    res4 = login('qwe', '123123')
    print(res1)
    print(res2)
    print(res3)
    print(res4)
    
    # 账号认证失败
    # 密码认证失败
    # 账号认证失败
    # 登录成功
    # False
    # False
    # False
    # True

    带参装饰器(def wrap(参数们))

    # 通过带参装饰器,实现增加颜色选择功能
    def color_choice(color_inp):
        def wrap(fn):
            if color_inp == 'red':
                info = 'red:new action'
            else:
                info = 'yellow:new action'
            
            def inner(*args, **kwargs):
                res = fn(*args, **kwargs)
                print(info)
                return res
            
            return inner  # wrap(fn) 返回的是 inner函数对象(地址)
        
        return wrap  # color_choice 返回的是 wrap函数对象 color_choice(color_inp)() => wrap() => res
    
    
    color_inp = input('color:')
    
    
    @color_choice(color_inp)
    def func():
        print('func run ')
    
    
    func()

    案例:查看个人主页前的登录状态验证

    is_login = False
    
    
    def login():
        usr = input('usr:').lower()
        if not (len(usr) >= 3 and usr.isalnum()):
            print('密码认证失败')
            return False
        pwd = input('pwd:')
        if usr == 'qwe' and pwd == '123123':
            print('登录成功')
            is_login = True
        else:
            print('登录失败')
            is_login = False
    
    
    # 完成一个登录状态校验的装饰器
    def check_login(fn):
        def inner(*args, **kwargs):
            if is_login != True:
                print('你未登录')
                login()
            res = fn(*args, **kwargs)
            return res
        return inner
    
    
    # 查看个人主页功能
    @check_login
    def homepage():
        print('个人主页')
    
    @check_login
    # 销售功能
    def sell():
        print('销售页面')
        
    homepage()
  • 相关阅读:
    三级菜单python写法(递归写法)
    webstorm2018.1.6版本安装+破解+汉化
    sourceTree 的使用教程
    nodeppt的使用教程
    堆和栈的区别(转过无数次的文章)
    黎曼滤波在神经计算方面的应用
    深度学习笔记——PCA原理与数学推倒详解
    TCP/IP模型详解
    OSI7层模型详解
    CNN车型分类总结
  • 原文地址:https://www.cnblogs.com/qianzhengkai/p/10649456.html
Copyright © 2011-2022 走看看