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

    装饰器就是返回函数的实际运用,装饰器接受一个原函数作为参数,返回值是一个现函数,调用装饰器就可以在原函数调用前后进行操作,而不改变原函数。

    def now():
         print('2015-3-25')
    
    def log(func):
        def wrapper(*args, **kw):
            print('call %s():' % func.__name__)
            return func(*args, **kw)
        return wrapper
    
    log(now)()
    

    以上述代码为例,now为原函数,log为装饰器,log接受函数func作为输入参数,返回wrapper函数作为返回值,而wrapper函数在func函数调用前打印日志,wrapper函数可以接受任意参数的调用,代表原始函数的参数可以是任意形式的。

    最后的log(now)先返回wrapper,然后log(now)()就调用了wrapper(),而wrapper()首先打印了日志,然后返回了func(),而func()就是now()。

    也可以使用@log对now重新定义,这样now就是一个装饰器

    @log
    def now():
        print('2015-3-25')
    

    这样就相当于运行了now=log(now),因此直接运行now()就达到了上面的效果,但是now函数名指向的函数定义变化了。

    如果装饰器本身需要输入参数,由于装饰器只能接受函数作为参数,所以又要在装饰器外面再套一层高阶函数,传入所需的参数,将装饰器函数作为最终的返回值返回  

    如下所示:

    def log(text):
        def decorator(func):
            def wrapper(*args, **kw):
                print('%s %s():' % (text, func.__name__))
                return func(*args, **kw)
            return wrapper
        return decorator
    

    调用时可以log('想要打印的日志')(now)(),也可以在原函数定义前加@log('想要打印的日志')

    如果使用了装饰器重新定义函数,那么它的__name__等属性就变为了wrapper,因此需要在装饰器定义前加上@functools.wraps(func)

    import functools
    
    def log(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('call %s():' % func.__name__)
            return func(*args, **kw)
        return wrapper
    

    作业有个思考题解法很有意思

    import functools
    def log(args):
        if isinstance(args,str):
            def dec(func):
                @functools.wraps(func)
                def wrapper(*a,**kw):
                    print('begin func',args)
                    func(*a,**kw)
                    print('end func')
                return wrapper
            return dec
        else:
            @functools.wraps(args)
            def wrapper(*a, **kw):
                print('begin func', args)
                args(*a, **kw)
                print('end func')
            return wrapper
    @log('execute')
    def f():
        print('I am here')
    @log
    def f():
        print('I am here')
    f()
    

    @log

    def f():

      pass

    等价于 f=log(f)

    @log('execute')

    def f():

      pass

    等价于f=log('execute')(f)  

    解法中根据log()括号中的参数类型是否为字符串来判断,如果参数为字符串,那么属于三层嵌套的装饰器,如果参数不是字符串,那么就将args作为被调用的函数名参数,即两层嵌套。  

    课外阅读:

    http://www.cnblogs.com/myd7349/p/how_to_use_wraps_of_functools.html 

  • 相关阅读:
    Token 分析
    maven导入依赖下载jar包速度太慢
    springboot 自动装配
    @ComponentScan
    mysql8.0忘记密码或出现Access denied for user 'root'@'localhost' (using password: YES)
    SpringBoot静态资源处理
    @RestController
    PythonGUI:Tkinter学习笔记01
    Python2和Python3有什么区别?
    Python的Random模块
  • 原文地址:https://www.cnblogs.com/vonkimi/p/6901693.html
Copyright © 2011-2022 走看看