您的位置:首页 > 编程语言 > Python开发

21-Python 装饰器

2020-10-26 08:08 896 查看

简明python 装饰器介绍

简言之,python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。

一般而言,我们要想拓展原来函数代码,最直接的办法就是侵入代码里面修改,例如:

这是我们最原始的的一个函数,然后我们试图记录下这个函数执行的总时间,那最简单的做法就是:

但是如果你的Boss在公司里面和你说:“这段代码是我们公司的核心代码,你不能直接去改我们的核心代码。”那该怎么办呢,我们仿照装饰器先自己试着写一下:

这里我们定义了一个函数deco,它的参数是一个函数,然后给这个函数嵌入了计时功能。然后你可以拍着胸脯对老板说,看吧,不用动你原来的代码,我照样拓展了它的函数功能。

然后你的老板有对你说:“我们公司核心代码区域有一千万个

func()
函数,从func01()到func1kw(),按你的方案,想要拓展这一千万个函数功能,就是要执行一千万次deco()函数,这可不行呀,我心疼我的机器。

”好了,你终于受够你老板了,准备辞职了,然后你无意间听到了装饰器这个神器,突然发现能满足你的要求了。

我们先实现一个最简陋的装饰器,不使用任何语法糖和高级语法,看看装饰器最原始的面貌:

这里的deco函数就是最原始的装饰器,它的参数是一个函数,然后返回值也是一个函数。其中作为参数的这个函数

func()
就在返回函数
wrapper()
的内部执行。

然后在函数

func()
前面加上
@deco
func()
函数就相当于被注入了计时功能,现在只要调用
func()
,它就已经变身为“新的功能更多”的函数了。

所以这里装饰器就像一个注入符号:有了它,拓展了原来函数的功能既不需要侵入函数内更改代码,也不需要重复执行原函数。

然后你满足了Boss的要求后,Boss又说:“我让你拓展的函数好多可是有参数的呀,有的参数还是个数不定的那种,你的装饰器搞的定不?”然后你嘿嘿一笑,深藏功与名

最后,你的老板说:“可以的,我这里一个函数需要加入很多功能,一个装饰器怕是搞不定,装饰器能支持多个嘛” 最后你就把这段代码丢给了他:

多个装饰器执行的顺序就是从最后一个装饰器开始,执行到第一个装饰器,再执行函数本身。盗用别人的例子:

输出:

functools.wraps

Python提供给我们一个简单的函数来解决这个问题,那就是functools.wraps。我们修改上一个例子来使用functools.wraps:

from functools import wraps

def a_new_decorator(a_func):
@wraps(a_func)
def wrapTheFunction():
print("在执行之前我在做一些无聊的工作 a_func()")
a_func()
print("在执行之后我在做一些无聊的工作 a_func()")
return wrapTheFunction

@a_new_decorator
def a_function_requiring_decoration():
"""Hey yo! 来装饰我有!"""
print("我是需要一些装饰的功能
“除掉我的臭味 ")

print(a_function_requiring_decoration.__name__)
# Output: a_function_requiring_decoration

我的第一个装饰器

from functools import wraps
def decorator_name(f):
@wraps(f)
def decorated(*args, **kwargs):
if not can_run:
return "函数将没有执行"
return f(*args, **kwargs)
return decorated

@decorator_name
def func():
return("函数执行")

can_run = True
print(func())
# 输出 函数执行

can_run = False
print(func())
#  输出 函数将没有执行

注意:

@wraps
接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。

这可以让我们在装饰器里面访问在装饰之前的函数的属性。

使用场景

授权(Authorization):

from functools import wraps

def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
authenticate()
return f(*args, **kwargs)
return decorated

日志(Logging):

from functools import wraps

def logit(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging

@logit
def addition_func(x):
"""Do some math."""
return x + x

result = addition_func(4)
# Output: addition_func was called

在函数中嵌入装饰器:

from functools import wraps

def logit(logfile='out.log'):
def logging_decorator(func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + " was called"
print(log_string)
# 打开logfile,并写入内容
with open(logfile, 'a') as opened_file:
# 现在将日志打到指定的logfile
opened_file.write(log_string + '\n')
return func(*args, **kwargs)
return wrapped_function
return logging_decorator

@logit()
def myfunc1():
pass

myfunc1()
# Output: myfunc1 was called
# 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串

@logit(logfile='func2.log')
def myfunc2():
pass

myfunc2()
# Output: myfunc2 was called
# 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串

sofiiii:https://www.jianshu.com/p/2b372d38fb3c

阿平搞Python:https://www.jianshu.com/p/95e04256264d

IT入门 感谢关注

程序员题库→

程序员用的单词表→

练习地址:www.520mg.com/it

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: