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

    1、定义:假设我们要增强一个函数的功能,比如,在函数调用前后自动打印日志,但又不希望改变这个函数的源代码,这种在代码运行期间动态增加功能且又不改变源代码的方式,成为装饰器(Decorator)。本质上,decorator就是一个返回函数的高阶函数

    2、示例:

      

      如上图中的原函数为index(),我们通过装饰器为其增加了一个计算运行时间的功能,但是没有改变源代码,这就是为其增加了一个装饰器,装饰器的功能就是计时。

      关键点:@的语法,@timmer等同于进行了如下操作:index=timmer(index),函数名+()就是调用函数,一定要记住!!好多地方想不通原因就是在这里!

          思想就是把部内函数func()换成被装饰函数index()然后再运行闭包函数就好了(可能说的有点简单)

    3、复杂一点的例子,代参数的,并且是用于多个参数不确定的函数的装饰器

    import time
    def timmer(func):
        def wrapper (*args,**kwargs):##注意注意*args和**kwargs
            start_time=time.time()
            func(*args,**kwargs)##注意注意*args和**kwargs
            stop_time=time.time()
            print("run time is %s"%(stop_time-start_time))
        return wrapper
    @timmer##注意注意位于被装饰函数最上方,且单独占一行
    def home(name):
        time.sleep(2)
        print("welcome to %s home page"%name)
    
    @timmer
    def auth(name,password):
        print(name,password)
    
    @timmer
    def tell():
        print('=======')
    home('dragon')
    auth('egon','123')
    tell()
    

    4、装饰用户认证功能

    #现在是对index()函数增加了用户认证功能,源代码没有变
    def auth2(auth_type): def auth(func): def wrapper(*args,**kwargs): if auth_type == 'file': name=input('username:') password=input('password:') if name=='zhejiangf4'and password == 'sbasb': print('auth successful') res=func(*args,**kwargs) return res else: print('auth error') elif auth_type =="sql": print("还他妈不会玩") return wrapper return auth @auth2(auth_type="file") #==>@auth==>index=auth(index),所以auth2作用就是传了一个值 def index(): print('Welcome to index page!') index()

    5、再给上面的函数加一个时间模块

    import time
    def timmer(func):
        def wrapper():
            start_time=time.time()
            func()
            stop_time=time.time()
            print(stop_time-start_time)
        return wrapper
    def auth2(auth_type):
        def auth(func):
            def wrapper(*args,**kwargs):
                if auth_type == 'file':
                    name=input('username:')
                    password=input('password:')
                    if name=='zhejiangf4'and password == 'sbasb':
                        print('auth successful')
                        res=func(*args,**kwargs)
                        return res
                    else:
                        print('auth error')
                elif auth_type =="sql":
                    print("还他妈不会玩")
            return wrapper
        return auth
    @timmer
    @auth2(auth_type="file")#
    def index():
        print('Welcome to index page!')
    index()
    

      上面函数的运行原理需要细说一下

    #先把大体的概念说一下:
    # def aaa():#装饰函数
    # @aaa
    # def func():#被装饰函数
    #     pass
    #
    # func=aaa(func)
    
    # @ccc
    # @bbb
    # @aaa
    # def func():
    #     pass
    #
    # func=ccc(bbb(aaa(func)))
    
    #
    # @ccc('c')
    # @bbb('b')
    # @aaa('a')
    # def func():
    #     pass
    #
    # func=ccc('c')(bbb('b')(aaa('a')(func)))
    
    #上边的例子是下边这个规律
    #founc=bbb(aaa('a')(func))
    #index=timmer(auth2(auth_type="list")(func))
    #index=timmer(auth(func))
    #index=timmer(wrapper_dixia)
    #index=wrapper_shangbian
    #index()=wrapper_shangbian()
    #index()=wrapper_dixia()
    

    6、eval函数:会把字符串里面的东西读出来执行,结果必须要赋值,不然砸电脑

    m=input(">>:")
    m=eval(m)
    print(m,type(m))
    
    >>:{"name":"agon"}
    {'name': 'agon'} <class 'dict'>
    >>:["agon"]
    ['agon'] <class 'list'>
    >>:print(123)
    

    7、给认证装饰器增加一个登陆后再次调用是免认证的功能(字典,只在内存中能行)

    import time
    current_login={'name':None,'login':False}#建立一个字典,字典存储登录状态
    def timmer(func):
        def wrapper():
            start_time=time.time()
            func()
            stop_time=time.time()
            print('run time is %s'%(stop_time-start_time))
        return wrapper
    def auth2(auth_type='file'):
        def auth(func):
            def wrapper(*args,**kwargs):
                if current_login['name'] and current_login['login']:#判断状态是否被激活,若激活直接执行函数结束
                    res=func(*args,**kwargs)
                    return res
                if auth_type == 'file':
                    name = input('username:')
                    password = input('password:')
                    if name == 'zhejiangF4' and password == 'sb945':
                        print('auth successful')
                        res = func(*args,**kwargs)
                        current_login['name']=name#存储登录状态
                        current_login['login']=True
                        return res
                    else:
                        print('auth error')
                elif auth_type == "sql":
                        print("haibuhui")
            return wrapper
        return auth
    @timmer
    @auth2(auth_type="file")
    def index():
        print('welcome to index page')
    @auth2("file")
    def home():
        print("welcome to home page")
    
    index()
    home()#第一次执行index()函数是需要登录认证,但第二次执行home时就不需要再认证了
    

    8、怎样在增加装饰器后还可以打印原函数的注释内容

    import time
    from functools import wraps#从函数工具中调用wraps模块
    def timmer(func):
        @wraps(func)#它就可以让你打印出的index.__doc__编程原函数的"dashabi"而不是wrapper函数的"000"
        def wrapper(*args,**kwargs):
            '000'
            start_time=time.time()
            res=func(*args,**kwargs)
            stop_time=time.time()
            print('run time is %s'%(stop_time-start_time))
            return res
        return wrapper
    @timmer
    def index():
        "dashabi"
        print("from index")
    index()
    print(index.__doc__)
    

      

  • 相关阅读:
    segnet 编译与测试
    ubuntu(已经配置了python2+opencv)简易配置python3的opencv:
    OCR光学字符识别--STN-OCR 测试
    阿里云图形界面
    win10+UEFI下u盘安装ubuntu16.04
    ubuntu16.04+cuda8.0+cudnn5.0+caffe
    Angular 组件通讯、生命周期钩子 小结
    Angular 路由⑦要素
    关于克隆gitlab项目的一些 问题列表
    RxJS学习笔记
  • 原文地址:https://www.cnblogs.com/wuyongqiang/p/6690004.html
Copyright © 2011-2022 走看看