廖雪峰的python笔记(八)--函数式编程之装饰器

  • 增强now()函数的功能:在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
  • 本质上是一个返回函数的高阶函数
def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

使用:
@log#==>now=log(now)
def now():
    print('2015-3-25')

输出:
>>> now()
call now():
2015-3-25
  • 如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂
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('execute')
def now():
    print('2015-3-25')

输出:
>>> now()
execute now():
2015-3-25
  • 两种decorator的定义都没有问题,还需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。
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(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

练习

1.请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:

def metric(func):
    @functools.wraps(func)
    def wraps(*args,**kw):
        start=time.time()
        res=func(*args,**kw)
        end=time.time()
        print("%s runned in %s seconds"%func.__name__,(end-start)*1000)
        return res
    return wraps

2.请编写一个decorator,能在函数调用的前后打印出'begin call''end call'的日志。

[https://blog.csdn.net/jiaowosiye/article/details/79272721]

def metric(func):
    @functools.wraps(func)
    def wrapper(*args,**kw):
        print("begin call %s():"%func.__name__)//begin
        res=func(*args,**kw)
        print("the result of the program is {}".format(res))//获取输出
        print("end call %s():"%func.__name__)//end
        return res
    return wrapper

3.思考一下能否写出一个@log的decorator,使它既支持:

[https://blog.csdn.net/jiaowosiye/article/details/79272721]

@log
def f():
    pass

又支持:

@log('execute')
def f():
    pass

def log(text):
    def decorator(func):
    @functools.wraps(func)
    def wrapper(*args,**kw):
        if text!=None:
            print("the text is %s and the call %s(): "%(text,func.__name__))
            res=func(*args,**kw)
            return res
        else: print("call %s ():"%func.__name__)
            res=func(*args,**kw)
            return res
        return wrapper
    if isinstance(text,str): #首先如果有参数 就跟原来一样直接返回decorator即可
        return decorator
    else: #如果没有参数 其实log(func)就是log里边其实直接传的参数就是func 返回的应该是wrapper 
        func=text
        text=None
        return decorator(func) #所以这里的应该是直接decorator(func) 返回wrapper 

猜你喜欢

转载自blog.csdn.net/weixin_38715903/article/details/87978136