一套网站设计多少钱,房地产公司网站 源码,建设银行中国建设银行,windows系统没有wordpress---1---
假设我们要增强某个函数的功能#xff0c;比如#xff0c;在函数调用前后自动打印日志#xff0c;但又不希望修改某个函数的定义#xff0c;这种在代码运行期间动态增加功能的方式#xff0c;称之为“装饰器”#xff08;Decorator).
装饰器本质上是一个Python…---1---
假设我们要增强某个函数的功能比如在函数调用前后自动打印日志但又不希望修改某个函数的定义这种在代码运行期间动态增加功能的方式称之为“装饰器”Decorator).
装饰器本质上是一个Python函数它可以让其他函数在不需要做任何代码变动的前提下增加额外功能装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景比如插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计有了装饰器我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲装饰器的作用就是为已经存在的对象添加额外的功能。
---2---
本质上decorator就是一个返回函数的高阶函数。所以我们要定义一个能打印日志的decorator.
观察下面的代码:
def log(func):def wrapper(*args, **kw):print(call %s(): % func.__name__)return func(*args, **kw)return wrapper
log
def now():print(2015-3-25)
把log放到now()函数的定义处相当于执行了语句
now log(now)
由于log()是一个decorator返回一个函数所以原来的now()函数仍然存在只是现在同名的now变量指向了新的函数于是调用now()将执行新函数即在log()函数中返回的wrapper()函数。
wrapper()函数的参数定义是(*args, **kw)因此wrapper()函数可以接受任意参数的调用。在wrapper()函数内首先打印日志再紧接着调用原始函数。
---3---
如果decorator本身需要传入参数那就需要编写一个返回decorator的高阶函数写出来会更复杂。比如要自定义log的文本
def log(text):def decorator(func):def wrapper(*args, **kw):print(%s %s(): % (text, func.__name__))return func(*args, **kw)return wrapperreturn decorator这个3层嵌套的decorator用法如下
log(execute)
def now():print(2015-3-25)
和两层嵌套的decorator相比3层嵌套的效果是这样的 now log(execute)(now)
我们来剖析上面的语句首先执行log(execute)返回的是decorator函数再调用返回的函数参数是now函数返回值最终是wrapper函数。
以上两种decorator的定义都没有问题但还差最后一步。因为我们讲了函数也是对象它有__name__等属性但你去看经过decorator装饰之后的函数它们的__name__已经从原来的now变成了wrapper now.__name__
wrapper因为返回的那个wrapper()函数名字就是wrapper所以需要把原始函数的__name__等属性复制到wrapper()函数中否则有些依赖函数签名的代码执行就会出错。
不需要编写wrapper.__name__ func.__name__这样的代码Python内置的functools.wraps就是干这个事的所以一个完整的decorator的写法如下
import functoolsdef log(func):functools.wraps(func)def wrapper(*args, **kw):print(call %s(): % func.__name__)return func(*args, **kw)return wrapper或者针对带参数的decorator
import functoolsdef log(text):def decorator(func):functools.wraps(func)def wrapper(*args, **kw):print(%s %s(): % (text, func.__name__))return func(*args, **kw)return wrapperreturn decorator
上面的东西看的一知半解的,看完下面的这一段应该会好点:
def check_is_admin(f):def wrapper(*args,**kwargs):if kwargs.get(username) ! admin:raise Exception(This user is not allowed to get food)return f(*args, **kwargs)return wrapperclass Storage(object):check_is_admindef get_food(self, username,food):return Storage.get(food)check_is_admindef put_food(self,username,food):return Storage.put(food) 参考:
(1).https://www.liaoxuefeng.com/wiki/1016959663602400/1017451662295584(廖雪峰官方文档)
(2).https://www.zhihu.com/question/21408921/answer/129036707 (怎样才能写出 Pythonic 的代码)
(3).https://www.zhihu.com/question/26930016/answer/99243411 (如何理解Python装饰器)