zoukankan      html  css  js  c++  java
  • Python装饰器

    1.装饰器

    • 开放封闭原则

    所以装饰器最终最完美的定义就是:在不改变原被装饰的函数的源代码以及调用方式下,为其添加额外的功能。

    2.装饰器初始

    装饰器就是一个函数

    范例

    def inex():
        time.sleep(2)
        print("欢迎....")
    
    def func(x):		
        def func2():
            start_time = time.time()
            x() #由于传入的实参是index 所以这里是index();下相当于闭包 x是自由变量
            end_time = time.time()
            print(end_time - start_time)
        return func2
    
    index = func(inex)  #代码走到这里会执行 func(index);将index做为实参传给func(x)->func(index);执行完return func2(这个func2也就是里边嵌套的函数)
    index()     #这个也就是执行func2那个函数
    >>>
    欢迎....
    2.00072979927063
    

    2.1 由上方演变的装饰器标准版初

    #定义一个装饰器的函数
    def func1(func_name):
        def func2():
            start_time = time.time()
            func_name()
            end_time = time.time()
            print(end_time - start_time)
        return func2
    @func1          #装饰器中的语法糖;这里等用于 index = func1(index);注意此处@func1和下面的def index是结合的
    def index():
        time.sleep(1)
        print("欢迎")
        return 666
    index()
    
    @func1          #每次需要调用装饰器的时候 都要在此函数头上加上一个@func1(语法糖)
    def come():
        time.sleep(1)
        print('login')
    come()
    

    2.2 带有返回值的装饰器

    #带有返回值的装饰器
    def func2(x):
        def func3():
            start_time = time.time()
            ret = x()
            end_time = time.time()
            print(end_time - start_time)
            return ret
        return  func3
    @func2                  #使用语法糖声明装饰器(与下边的func函数)
    def func():
        time.sleep(0.5)
        print("欢迎登录博客...")
        return 666          #此返回值是func函数的返回值 ;重点是”func“这个函数是装饰器里边的 x()所调用的 所以要给x()赋一个值 并return
    ret = func()
    print(ret)
    print(func())
    >>>
    欢迎登录博客...
    0.5008265972137451
    666
    欢迎登录博客...
    0.5003719329833984
    666
    

    2.3 带参数的装饰器

    def func2(x):
        def func3(name):
            print(name)
            start_time = time.time()
            ret = x(name)
            end_time = time.time()
            print(end_time - start_time)
            return ret
        return  func3
    # @func2                  #使用语法糖声明装饰器(与下边的func函数)
    def func(name):
        time.sleep(0.5)
        print(f"欢迎登录{name}博客...")
        return 666          #此返回值是func函数的返回值 ;重点是”func“这个函数是装饰器里边的 x()所调用的 所以要给x()赋一个值 并return
    
    ret = func2(func)       #执行这部会调用上方的 func2函数 func2的函数返回值是 func3 所以这时 ret 就等于 func3
    ret('liu')             #执行到这 会调用上方的 fun3函数 并将'liu'传给func3(name)位置参数 再将name传给x(name->'liu')
    
    #加上语法糖
    def func2(x):
        def func3(name):
            print(name)
            start_time = time.time()
            ret = x(name)
            end_time = time.time()
            print(end_time - start_time)
            return ret
        return  func3
    @func2                  #使用语法糖声明装饰器(与下边的func函数)
    def func(name):
        time.sleep(0.5)
        print(f"欢迎登录{name}博客...")
        return 666          #此返回值是func函数的返回值 ;重点是”func“这个函数是装饰器里边的 x()所调用的 所以要给x()赋一个值 并return
    func('liu')
    >>>
    liu
    欢迎登录liu博客...
    0.5000627040863037
    

    2.4 万能参数的标准版的装饰器

    def func2(x):
        def func3(*args,**kwargs):#函数的定义 函数的聚合 * args 
    
            start_time = time.time()
            ret = x(*args,**kwargs)
            #函数的执行 * 打散:x(*args) -->x(*(‘liu’,22)) --> x(‘liu’,22)
            end_time = time.time()
            print(end_time - start_time)
            return ret
        return  func3
    @func2                  #使用语法糖声明装饰器(与下边的func函数)
    def func(name,age,hobby='运动'):
        time.sleep(0.5)
        print(f"欢迎登录{name}{age}岁博客爱好{hobby}...")
        return 666          #此返回值是func函数的返回值 ;重点是”func“这个函数是装饰器里边的 x()所调用的 所以要给x()赋一个值 并return
    func('liu',10,hobby='python')
    # ret = func2(func)       #执行这部会调用上方的 func2函数 func2的函数返回值是 func3 所以这时 ret 就等于 func3
    # ret('liu')             #执行到这 会调用上方的 fun3函数 并将'liu'传给func3(name)位置参数 再将name传给x(name->'liu')
    @func2
    def blog(name,age):
        print(f'欢迎使用{name},{age}岁的日志功能...')
    
    blog('Liu',15)
    
    def func2(x):
        def func3(*args,**kwargs):
            for i in args:
                print(i)
            for k, v in kwargs.items():
                print(k, v)
            start_time = time.time()
            ret = x(*args,**kwargs)
            end_time = time.time()
            print(end_time - start_time)
            return ret
        return  func3
    @func2                  #使用语法糖声明装饰器(与下边的func函数)
    def func(name,age,hobby='运动'):
        time.sleep(0.5)
        print(f"欢迎登录{name}{age}岁博客爱好{hobby}...")
        return 666          #此返回值是func函数的返回值 ;重点是”func“这个函数是装饰器里边的 x()所调用的 所以要给x()赋一个值 并return
    func('liux',10,hobby='python')
    # ret = func2(func)       #执行这部会调用上方的 func2函数 func2的函数返回值是 func3 所以这时 ret 就等于 func3
    # ret('liu')             #执行到这 会调用上方的 fun3函数 并将'liux'传给func3(name)位置参数 再将name传给x(name->'liux')
    @func2
    def blog(name,age):
        print(f'欢迎使用{name},{age}岁的日志功能...')
    
    blog('Liu',15)
    
    

    2.5 最终版的装饰器

    def wrapper(f):
        def inner(*args,**kwargs):
            ''' 添加额外的功能:执行被装饰函数之前的操作 '''
            ret = f(*args,**kwargs)
            ''' 添加额外的功能:执行被装饰函数之后的操作'''
            return ret
        return inner
    

    3.装饰器的应用

    实现基于用户登录成功以后才能执行 comment() darit() 函数

    user_info = {}
    def register():
        user = input('请输入注册的用户:')
        passwd = input('请输入注册的密码:')
        user_info[user] = passwd
    def login():
        count = 1
        while count < 4:
            username = input('请输入您的用户名:')
            userpasswd = input('请输入您的密码:')
            if username not in user_info.keys():
                print('sorry,您的用户不存在需要注册~')
                register()
            elif username in user_info.keys() and userpasswd == user_info.get(username):
                print('登录成功')
                return 1
    
            else:
                print('sorry 输入有误')
                count += 1
    dic = {'status':0}
    def wrapper(f):
        def inner(*args,**kwargs):
            if dic.get('status') == 1:
                ret = f(*args, **kwargs)
            else:
                login_ret = login()
                if login_ret == 1:
                    dic['status'] =1
                    ret = f(*args, **kwargs)
        return inner
    
    
    @wrapper
    def comment():
        print('欢迎访问评论页面.')
    
    comment()
    @wrapper
    def darit():
        print('欢迎访问日记页面')
    
    darit()
    
    

    4. 装饰器例子

    def timmer(*args,**kwargs):
        c = args
        dct = kwargs
        def tim(func):
    
            def time(*args,**kwargs):
                print('start...')
                res = func(*args,**kwargs)
                print('end...')
                print(c,dct)
               # print(name)
                return res
            return time
        return tim
    
    
    
    @timmer('liu',18,name='liu') #f1=f(f1)
    def f1(x,y,z):
        print(f'from f1...{x} {y} {z}')
    @timmer
    def f2(x,y,z):
        print(f'from f1...{x} {y} {z}')
        return 123
    
    f1(1,2,3)
  • 相关阅读:
    SVN还原项目到某一版本(转)
    C# Web Service 不使用服务引用直接调用方法(转)
    动态调用webservice时 ServiceDescriptionImporter类在vs2010无法引用的解决方法 (转)
    log4net示例2-日志输入存入Access(转)
    C# log4net 配置及使用详解--日志保存到文件和Access(转)
    未能解析引用的程序集......因为它对不在当前目标框架“.NETFramework,Version=v4.0,Profile=Client”中的 (转)
    Hello log4net——做一个实用好用的log4net的demo(转)
    JS移动客户端--触屏滑动事件
    js生成二维码实例
    触屏版类似刷新页面文本框获取焦点的同时弹出手机键盘的做法
  • 原文地址:https://www.cnblogs.com/precipitation/p/15098563.html
Copyright © 2011-2022 走看看