Python学习笔记__4.4章 装饰器(添加额外功能)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python学习笔记__4.4章 装饰器(添加额外功能)相关的知识,希望对你有一定的参考价值。

# 这是学习廖雪峰老师python教程的学习笔记

1、概览

装饰器可以帮助我们为已经存在的对象添加额外的功能

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。

装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事物处理、缓存、权限校验等场景。

1.1、为now函数 加一行日志

# 定义now函数

def now():

    print('2018-5-8')

 

# 编辑decorator

def log(func):        # 接受函数名

    def wrapper(*args,**kw):   # 接收传入函数的参数

        print('the function name is %s():' % func.__name__)  # 打印函数的__name__属性,注意__name__ 是两条_(下划线)

        return func(*args,**kw)    # 返回这个函数

    return wrapper

 

# 将decorator 加到 now函数

@log

def now():

    print('2018-5-8')

 

把@log放到now()函数的定义处,相当于执行了 now=log(now)。过程为【wapper=log(now),weapper返回now()】

由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。

 

1.2、三层嵌套的decorator

如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数。比如,要自定义log的文本

def log(text):

    def decorator(func):

        def wrapper(*args, **kw):

            print('%s %s():' % (text, func.__name__))

            return func(*args, **kw)

        return wrapper

    return decorator

 

# 添加到now() 函数

@log('execute')

def now():

    print('2015-3-25')

 

#  效果

>>> now()

execute now():

2015-3-25

 

三层嵌套的执行效果:now = log('execute')(now)

 

1.3、原始函数的属性复制

从上面的例子可以看出,now()函数 最终是由wrapper 函数返回的。 此时now() 函数的__name__属性已经变为了 'wrapper'

>>> now.__name__

'wrapper'

但我们的本意只是,给now() 函数加额外功能,并不想改变它本身的属性,此时,就需要把now() 函数的属性复制给 wrapper() 函数

不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的

functools.wrapswraps 本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中。这使得装饰器函数也有和原函数一样的元信息

# 顺便复制属性的decorator

import functools

 

def log(func):

    @functools.wraps(func)   #这个装饰器始终在 wrapper 函数上面

    def wrapper(*args, **kw):

        print('call %s():' % func.__name__)

        return func(*args, **kw)

    return wrapper

 

2、例子

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

# -*- coding: utf-8 -*-
import time, functools

def metric(fn):

    @functools.wraps(fn)   # 复制原函数信息 wrapper

    def wrapper(*args, **kw):

        begin=time.time()

        res=fn(*args, **kw)  # fn 函数的返回值 赋给 res

        end=time.time()

        print("%s executed in %s ms" % (fn.__name__,(end-start)*1000))  # 打印执行时间 ms

        return res

    return wrapper

 

2、在函数的执行前后打印标记

def log(func):

def call(*args,**kw):

print('begin call')

out=func(*args,**kw)   # 要点在于 将函数的返回值 赋值给一个变量,最后return 变量

print('end call')

return out

return call


以上是关于Python学习笔记__4.4章 装饰器(添加额外功能)的主要内容,如果未能解决你的问题,请参考以下文章

python学习笔记:装饰器2

Python学习笔记__3.5章 迭代器

python_类装饰器

python3 装饰器修复技术@wraps到底是什么?

Python学习笔记__12.7章 itertools

Python学习日记简单了解迭代器生成器装饰器上下文管理器