zoukankan      html  css  js  c++  java
  • 巨蟒python全栈开发-第15天 装饰器

    一.今日内容总览

    关于函数的装饰器
    1.装饰器(重点,难点)(要求:反复写,代码不多但是很绕)
    开闭原则:(比如,菜单是拆散的,一点点搞的,用友拆散自己的功能,以后就不用开发了)
    (1)对功能的扩展开放
    (2)对代码的修改是封闭的

    通用装饰器语法:
    def wrapper(fn):
    def inner(*args,**kwargs): #聚合
    #在目标函数之前的操作
    ret=fn(*args,**kwargs) #打散
    在目标函数之后
    return inner
    @wrapper #等价于 func=wrapper(func)
    def func():
    pass
    func()

    NC(用友,脑残)
    2.同一个函数 被多个装饰器装饰

    @wrapper1
    @wrapper2
    @wrapper3
    def func():
    pass
    1 2 3 func 3 2 1
    总结:就近原则,一层一层写

    3.带参数的装饰器(难受)(明白函数的调用就行)
    def wrapper_out(参数):
    def wrapper(fn):
    def inner(*args,**kwargs): #聚合
    #在目标函数之前
    ret=fn(*args,**kwargs) #打散
    #在目标函数之后
    return ret
    return inner
    return wrapper
    @wrapper_out(实参) #执行的时候,先执行函数调用,然后使用返回值和前面的@组合成装饰器语法糖
    def func():
    pass

    二.今日内容大纲

    1.开闭原则

    2.装饰器

    3.带参数的装饰器

    4.多个装饰器装饰同一个函数

    5.装饰器的应用

    三.今日内容详解

    1.开闭原则

    开闭原则:
    对功能的扩展开放;
    对代码的修改是封闭的.
    def chi():
        print('吃东西')
        print('喝东西')
    chi()
    chi()
    #显然不是我们想要的,对程序继续优化

    2.装饰器

    (1)

    女娲  造人 补天
    热插拔:有时需要,有时不需要,这才是程序需要的
    def zaoren():
        # print('浇水')    #此需求有的时候需要,有的时候不需要
    
        print('捏个泥人')
        print('吹口仙气')
        print('就出来人了')
    zaoren()
    zaoren()
    zaoren()
    上面的写法依然没满足我们的需求

    (2)

    #三年大旱,没有水?
    def zaoren():
        # print('浇水')    #此需求有的时候需要,有的时候不需要
        print('捏个泥人')
        print('吹口仙气')
        print('就出来人了')
    def water():
        print('浇水')
        zaoren()
    zaoren()    #不能一直修改这两行代码
    water()
    #这时的设计就不符合开闭原则

    (3)装饰器的源头

    # # 装饰器
    def wrapper(fn): # fn接收的是一个函数
        def inner():
            print("浇水")
            fn() # 调用你传递进来的函数
            print("睡一觉")
        return inner
    def zaoren():
        print("捏个泥人")
        print("吹口仙气")
        print("你就出来了")
    zaoren = wrapper(zaoren)
    zaoren()
    zaoren()

    (4)lol & 消消乐

    #lol
    def lol():
        print('双击lol')
        print('选择狂战士')
        print('进草丛')
        print('崩山击,十字斩')
    #开心消消乐
    def kxxxl():
        print('双击消除')
        print('进入下一关')
        print('升级')
        print('继续玩')
    
    #开挂
    #关闭外挂
    def wrapper(fn):
        def inner():
            print('开挂')
            fn()
            print('关闭外挂')
        return inner
    #lol装饰器
    lol=wrapper(lol)
    lol()
    #
    #kxxxl装饰器
    kxxxl=wrapper(kxxxl)
    kxxxl()
    '''
    结果:
    开挂
    双击lol
    选择狂战士
    进草丛
    崩山击,十字斩
    关闭外挂
    开挂
    双击消除
    进入下一关
    升级
    继续玩
    关闭外挂
    '''

    (5)

    装饰器传参

    def play(username,password):
        print('双击lol')
        print('登录',username,password)
        print('选择狂战士')
        print('进草丛')
        print('崩山击,十字斩')
        return '十字斩刀者'
    def xiaoxiaole(qq):
        print('登录qq账号')
        print('消消乐')

    开挂
    关闭外挂
    在目标函数前和后插入一段新的代码,不改变原来的代码
    方法一:(投机版)
    def wrapper(fn):   #fn=play
        def inner(*args,**kwargs):#无敌传参 聚合接收到的是元组('alex',123)
            print('开挂')
            fn(*args,**kwargs)
            print('关闭外挂')
            return '十字斩刀者'
        return inner
    play=wrapper(play)      #play=inner   左边的play代表inner
    w=play('alex','123')
    print(w)            #在这里返回的是inner的return
    
    xiaoxiaole=wrapper(xiaoxiaole)
    xiaoxiaole(11010)
    方法二:
    def wrapper(fn):   #fn=play
        def inner(*args,**kwargs):#无敌传参 聚合接收到的是元组('alex',123)
            print('开挂')
            s=fn(*args,**kwargs)      #这里也有变化
            print('关闭外挂')
            return s            #这里返回的接收的是内部函数的,如果play没有返回值,返回None
        return inner
    play=wrapper(play)      #play=inner   左边的play代表inner
    w=play('alex','123')
    print(w)                  #在这里返回的是play的return

    (6)

    通用装饰器写法:(写10遍以上!!!)
    #python里面的动态代理
    #存在的意义:在不破坏原有函数和原有函数调用的基础上,给函数添加新的功能
    #inner相当于代理
    
    def wrapper(fn):        #fn是目标函数
        def inner(*args,**kwargs):      #为了目标函数的传参
            '''在执行目标函数之前'''
            ret=fn(*args,**kwargs)      #调用目标函数,ret是目标函数的返回值
            '''在执行目标函数之后的操作,可以加if判断等等'''
            return ret          #目标函数返回值返回,保证函数正常的结束
        return inner
    
    @wrapper #target_func=wrapper(target_func)
    def target_func():
        pass
    #target_func=wrapper(target_func)   #此时上面的fn就是target_func
    target_func()   #此时执行的是inner
    # #注意:不要用打印当成返回值
    
    

    3.带参数的装饰器

    def wrapper_out(flag):              #装饰器本身的参数
        def wrapper(fn):                #目标函数
            def inner(*args,**kwargs):  #目标函数执行需要的参数
                if flag==True:
                    print('问问金老板,最近行情怎么样啊?')
                    ret=fn(*args,**kwargs) #在执行目标函数之前
                    print('金老板再骗我,恨你')
                    return ret
                else:
                    ret=fn(*args,**kwargs)  #在执行目标函数之前
                    return ret
            return inner
        return wrapper
    @wrapper_out(True) #先执行wrapper_out(True) 返回一个装饰器wrapper  再和@拼接  @装饰器
                        # wrapper_out(True)
                        # yue=wrapper(yue)      #左边的yue返回值是inner,右边的yue才是真正的下面的yue
    def yue():  #被wrapper装饰
        print('走啊,约不?')
    yue()                                       #执行yue,这里的yue是指inner,

    结果测试:

    '''
    False:
    走啊,约不?
    
    True:
    问问金老板,最近行情怎么样啊?
    走啊,约不?
    金老板再骗我,恨你
    '''

    4.多个装饰器装饰同一个函数

    def wrapper1(fn):
        def inner(*args, **kwargs):
            print("1111111")
            ret = fn(*args, **kwargs)
            print("2222222")
            return ret
        return inner
    
    def wrapper2(fn):
        def inner(*args, **kwargs):
            print("3333333")
            ret = fn(*args, **kwargs)
            print("44444444")
            return ret
        return inner
    
    def wrapper3(fn):
        def inner(*args, **kwargs):
            print("555555")
            ret = fn(*args, **kwargs)
            print("666666")
            return ret
        return inner
    # 就近原则
    @wrapper1
    @wrapper2
    @wrapper3
    def func():
        print("我是可怜的func")
    func()
    #自己总结:把最终要执行的核心语句当成鱼的大刺对称吃鱼原则
    # 1 2 3  func 3 2 1

    5.装饰器的应用

    menu = ("查看", "添加", "修改", "删除", "退出")
    flag = False # 没登录
    
    def login():
        global flag
        username = input("请输入用户名:")
        password = input("请输入密码:")
        if username == "alex" and password == "123":
            flag = True
            print("登录")
        else:
            flag = False
            print("用户名密码错误")
    
    # 登录验证装饰器函数
    def login_verify(fn):
        def inner(*args, **kwargs):
            # 登录校验
            while 1:
                if flag == True:
                    ret = fn(*args, **kwargs)
                    return ret
                else:
                    print('对不起, 您还没有登录')
                    login()
        return inner
    
    def chakan():
        print("==============================查看")
    
    @login_verify
    def tianjia():
        print("============================添加")
    @login_verify
    def xiugai():
        print("=======================修改")
    @login_verify
    def shanchu():
        print("=========================删除")
    
    while 1:
        for i in range(len(menu)):
            print(i+1, menu[i])
        num = input("请输入你要执行的菜单:")
        if num == "1":
            chakan()
        elif num == "2":
            tianjia()
        elif num == "3":
            xiugai()
        elif num == "4":
            shanchu()
        elif num == "5":
            print("程序退出中..........")
            exit()
        else:
            print("输入有误. 请重新选择!")

    作业:

    1.整理装饰器的形成过程, 背诵装饰器的固定格式

    #装饰器通用写法
    #存在的意义:在不破坏原有函数和原有函数调用的基础上,给函数添加新的功能
    #inner相当于代理
    
    def wrapper(fn):     #fn是目标函数
        def inner(*args,**kwargs):   #为了目标函数的传参
            '''在执行目标函数之前的操作'''
            ret=fn(*args,**kwargs) #调用目标函数,ret是目标函数的返回值
            '''在执行目标函数之后的操作,可以加if判断等等'''
            return ret      #目标函数返回值返回,保证函数正常的结束
        return inner
    @wrapper #target_func=wrapper(target_func)
    def target_func():
        # print('1')
        pass
    #target_func=wrapper(target_func) #此时上面的fn就是target_func
    target_func()       #此时执行的是inner
    #注意:不要用打印当成返回值

    2.编写装饰器, 在每次执行被装饰函数之前打印”

    每次执行被装饰函数之都要先经过这里, 这里根据需求添加代码”

    def wrapper(fn):     #fn是目标函数
        def inner(*args,**kwargs):   #为了目标函数的传参
            '''在执行目标函数之前的操作'''
            ret=fn(*args,**kwargs) #调用目标函数,ret是目标函数的返回值
    
            return ret      #目标函数返回值返回,保证函数正常的结束
        return inner
    @wrapper #target_func=wrapper(target_func)
    def target_func():
        pass
    #target_func=wrapper(target_func) #此时上面的fn就是target_func
    target_func()       #此时执行的是inner
    3.编写装饰器, 在每次执行被装饰函数之前打印”
    每次执行被装饰函数之都要经过这里, 这里根据需求添加代码”
    def wrapper(fn):     #fn是目标函数
        def inner(*args,**kwargs):   #为了目标函数的传参
    
            ret=fn(*args,**kwargs) #调用目标函数,ret是目标函数的返回值
            '''在执行目标函数之后的操作,可以加if判断等等'''
            return ret      #目标函数返回值返回,保证函数正常的结束
        return inner
    @wrapper #target_func=wrapper(target_func)
    def target_func():
        pass
    #target_func=wrapper(target_func) #此时上面的fn就是target_func
    target_func()       #此时执行的是inner

    4.编写装饰器, 在每次执行被装饰函数之前让用户输入用户名, 

    密码, 给用户三次机会, 登录成功之后, 才能访问该函数

    
    
    def login():
        global flag
        count=1
    #方法一:
        # while 1:
        #     username = input("请输入用户名:")
        #     password = input("请输入密码:")
        #                                      #3次失败,直接离开整个程序
        #     if username == "alex" and password == "123":
        #         flag = True                             #重点:登陆成功之后,改变全局变量为True
        #         print("登录成功")                       #登陆成功,直接进入下一步
        #         break
        #     else:
        #         flag = False
        #         print("用户名密码错误")
        #     if count==3:                            #if放在下边和上边是不一样的
        #         exit()
        #     count+=1
        # else:
        #     print('您已经输入错误了3次')
    #方法二:
        # while count<4:
        #     username = input("请输入用户名:")
        #     password = input("请输入密码:")
        #                                      #3次失败,直接离开整个程序
        #     if username == "alex" and password == "123":
        #         flag = True                             #重点:登陆成功之后,改变全局变量为True
        #         print("登录成功")                       #登陆成功,直接进入下一步
        #         break
        #     else:
        #         flag = False
        #         print("用户名密码错误")
        #     # if count==3:                            #if放在下边和上边是不一样的
        #     #     exit()
        #     count+=1
        #     print(count)
        # else:
        #     print('您已经输入错误了3次')
        #     exit()
    #方法三:
        # for i in range(3):
        #     username = input("请输入用户名:")
        #     password = input("请输入密码:")
        #                                      #3次失败,直接离开整个程序
        #     if username == "alex" and password == "123":
        #         flag = True                             #重点:登陆成功之后,改变全局变量为True
        #         print("登录成功")                       #登陆成功,直接进入下一步
        #         break
        #     else:
        #         flag = False
        #         print("用户名密码错误")
        #     # if count==3:                            #if放在下边和上边是不一样的
        #     #     exit()
        #     count+=1
        #     print(count)
        # else:
        #     print('您已经输入错误了3次')
        #     exit()
    
    
    flag = False # 没登录
    def wrapper(fn):     #fn是目标函数
        def inner(*args, **kwargs):
            # 登录校验
            while 1:
                if flag == True:                        #问题:函数是怎么走这块的?
                    ret = fn(*args, **kwargs)
                    return ret
                else:
                    print('你好,请您登陆!')
                    login()
        return inner
    @wrapper #target_func=wrapper(target_func)
    
    def target_func():
        print('冬瓜你好')
    #target_func=wrapper(target_func) #此时上面的fn就是target_func
    target_func()       #此时执行的是inner
    
    
    5.编写装饰器, 为多个函数加上认证功能(用户的账户密码来源于文件, 
    用户有三次登录的机会), 要求, 如果用户登录成功了, 后续就不需要再次登录了.
    def login():
        global flag
        count=1
    #方法一:
        s=1
        while s:
            username = input("请输入用户名:")
            password = input("请输入密码:")
                                             #3次失败,直接离开整个程序
            with open('info', mode='r', encoding='utf-8') as f:
                for i in f.readlines():
                    t_user,t_pwd=i.split('|')
                    if username == t_user and password == t_pwd:
                        flag = True                             #重点:登陆成功之后,改变全局变量为True
                        print("登录成功")                       #登陆成功,直接进入下一步
                        # break
                        s=0
                    else:
                        flag = False
                        print("用户名密码错误")
                        count += 1                          #注意应该在这里,把每次错误的数字+1
    
                    if count == 4:  # if放在下边和上边是不一样的
                        print('您已经输入错误了3次')
                        exit()
        else:
            print('进入下一步')
    
    flag = False # 没登录
    def wrapper(fn):     #fn是目标函数
        def inner(*args, **kwargs):
            # 登录校验
            while 1:
                if flag == True:                        #问题:函数是怎么走这块的?
                    ret = fn(*args, **kwargs)
                    return ret
                else:
                    print('你好,请您登陆!')
                    login()
        return inner
    @wrapper #target_func=wrapper(target_func)
    
    def target_func():
        print('冬瓜你好')
    #target_func=wrapper(target_func) #此时上面的fn就是target_func
    target_func()       #此时执行的是inner
    6.给每个函数写一个记录日志的功能. 
    功能要求: 每一次调用函数之前, 要将函数名称, 事件节点记录到log的日志中.
    所需模块:
    import time
    print(time.strftime(“%Y-%m-%d %H:%M:%S”))
     
  • 相关阅读:
    yii2中的url美化
    一级域名301重定向到www二级域名
    使用meta来控制浏览器的渲染方式
    同一页面不同编码的提交处理
    Yii2.0 UrlManager
    sqlsever连接两个不同服务器上的数据库进行查询
    php 实现传入参数的传出
    xcode如何修改项目名称
    ios如何实现应用之间的跳转
    ios程序如何实现系统自带的分享
  • 原文地址:https://www.cnblogs.com/studybrother/p/10121641.html
Copyright © 2011-2022 走看看