zoukankan      html  css  js  c++  java
  • Python学习之路基础篇--11-12Python基础,函数的装饰器

      对于装饰器来说,就是在不改变函数的调用的情况下,对函数的前后增加了些许功能,这完全符合函数的 开放封闭 原则。装饰器的本质 其实就是一个闭包函数。

      这是一个装饰器的步骤图

    def wrapper(func):  # 2
        def inner(*args,**kwargs):  # 5
            ret = func(*args,**kwargs)  # 6
            return ret  #10
        return inner   # 3
    
    @wrapper  #shopping = wrappers(shooping)   # 1 --shopping = innner
    def shopping(num):  #7
        print(num)  # 8
        return 1    # 9
    
    print(shopping(5))  # 4

     

     

      这样你调 shopping 时, 真实情况是你在调用 inner 函数。如果 你想打印其函数名时打印的其实是 innner 函数。

    from functools import wraps
    def wrapper(func):  # 2
        @wraps(func)
        def inner(*args,**kwargs):  # 5
            ret = func(*args,**kwargs)  # 6
            return ret  #10
        return inner   # 3
    
    @wrapper  #shopping = wrappers(shooping)   # 1 --shopping = innner
    def shopping(num):  #7
        print(num)  # 8
        return 1    # 9
    
    print(shopping(5))  # 4
    print(shopping.__name__)  #以字符串的形式获取到函数名
    print(shopping.__doc__)  #以字符串的形式获取到函数注释

      如果用内置的模块,wraps ,就可以轻松解决这个问题,使得所有的还和以前一样,其中wraps(),中要传入参数,参数应该与外层装饰器的形参一致。

      对于装饰器,如果你想取消个这装饰器的功能,现在给出的方法就只能是在装饰的外面在套一个装饰器,并设置一个定位符(一个全局变量)来控制其是否执行:

    control = True
    def outer(flag):
            def wrapper(func):
                def inner(*args,**kwargs):
                    if flag:
                        print('函数执行前')
                        ret = func(*args,**kwargs)
                        print('函数执行后')
                        return ret
                    else:
                        ret = func(*args, **kwargs)
                return inner
            return wrapper
    
    @outer(control)# shoping = outer(shopping) = wapper(shoping) = inner(shopping) 只是要多一个参数进行判断
    def shopping(num):
        print(num)
        return 1
    
    shopping(5)

      

      多个装饰器进行嵌套,装饰器的糖的运行是,就近原则,离函数最近的糖先运行

    def wrapper1(func):  #func--shopping
        def inner(*args,**kwargs):
            print('000函数执行前')
            ret = func(*args,**kwargs)
            print('000函数执行后')
            return ret
        return inner
    
    def wrapper2(func):  #func--inner1
        def inner(*args,**kwargs):
            print('111函数执行前')
            ret = func(*args,**kwargs)  #这里的调用其实是使用 inner1() 函数
            print('111函数执行后')
            return ret
        return inner
    
    @wrapper2
    @wrapper1
    def shopping(num):
        print(num)
        return 1
    
    shopping(5)
    '''
    111函数执行前
    000函数执行前
    5
    000函数执行后
    111函数执行后
    '''

      来个作业

    # 在12 天作业 编写装饰器,为多个函数加上认证功能(用户的账号来源于文件),
    # 要求登入一次成功,后续的函数都无需再输入用户和密码
    def wrapper(func):
        def inner(*args, **kwargs):
            with open('ver', mode='r+',encoding='utf-8')as f:
               flag = f.read()
               if  flag:
                    verification = input('>>>').strip()
                    if verification == 'eli123':
                        # f.seek(0)
                        f.truncate(0,)
                        ret = func(*args, **kwargs)
                        return ret
               else:
                   ret = func(*args, **kwargs)
                   return ret
        return inner
    
    @wrapper
    def buy(num):
        print('买了{}个包子'.format(num))
    @wrapper
    def eat(num):
        print('吃了{}个包子'.format(num))
    with open('ver',mode='w',encoding='utf-8') as f:
        f.write('aaa')
    buy(3)
    eat(2)

      这里利用了一个文件,在进行函数前,生成内容,然后文件中有内容时,要求验证 验证码,然后删除,方便第二次的验证。

    # 2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
    from functools import wraps
    def wrapper(func):
        wraps(func)
        def inner(*args, **kwargs):
            with open('record',mode='a',encoding='utf-8') as f:
                f.write(func.__name__ + '
    ')
            ret = func(*args, **kwargs)
            return ret
        return inner
    
    @wrapper
    def buy(num):
        print('买了{}个包子'.format(num))
    @wrapper
    def eat(num):
        print('吃了{}个包子'.format(num))
    
    buy(3)
    eat(2)

      与第一题相比,确实比较容易一点(之后学到时间模块,可以加入时间模块的)

  • 相关阅读:
    【SPI】浅谈JDK中SPI技术
    【MySQL8.0.18】阿里云服务器上搭建MySQL数据库
    【JDK13】阿里云服务器安装JDK13
    小型个人博客搭建之数据库设计
    【算法题】CCF CSP第三题练习(更新中)
    【算法题】CCF CSP第一题练习
    【嵌入式】KEIL4和KEIL5合并
    【ROS】安装ubuntu18.04+ros-melodic
    Notepad++配置python之NppExec
    vi一般指令命令行
  • 原文地址:https://www.cnblogs.com/YS-0717/p/9450082.html
Copyright © 2011-2022 走看看