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

Python 装饰器

2020-02-01 13:46 459 查看

装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

1 import time
2
3 def show_time(func):
4     def wrapper():
5         start_time=time.time()
6         func()
7         end_time=time.time()
8         print('spend %s'%(end_time-start_time))
9
10     return wrapper
11
12
13 def foo():
14     print('hello foo')
15     time.sleep(3)
16
17 foo=show_time(foo)
18 foo()

函数show_time就是装饰器,它把真正的业务方法func包裹在函数里面,看起来像foo被上下时间函数装饰了。在这个例子中,函数进入和退出时 ,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。 

@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作

1 import time
2
3 def show_time(func):
4     def wrapper():
5         start_time=time.time()
6         func()
7         end_time=time.time()
8         print('spend %s'%(end_time-start_time))
9
10     return wrapper
11
12 @show_time   #foo=show_time(foo)
13 def foo():
14     print('hello foo')
15     time.sleep(3)
16
17
18 @show_time  #bar=show_time(bar)
19 def bar():
20     print('in the bar')
21     time.sleep(2)
22
23 foo()
24 print('***********')
25 bar()

装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。

带参数的被修饰函数

1 import time
2
3 def show_time(func):
4
5     def wrapper(a,b):
6         start_time=time.time()
7         func(a,b)
8         end_time=time.time()
9         print('spend %s'%(end_time-start_time))
10
11     return wrapper
12
13 @show_time   #add=show_time(add)
14 def add(a,b):
15
16     time.sleep(1)
17     print(a+b)
18
19 add(2,4)

装饰器带参数

import time

def time_logger(flag=0):

def show_time(func):

def wrapper(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs)
end_time=time.time()
print('spend %s'%(end_time-start_time))

if flag:
print('将这个操作的时间记录到日志中')

return wrapper

return show_time

@time_logger(3)    # add = time_loger(3)(add)
def add(*args,**kwargs):
time.sleep(1)
sum=0
for i in args:
sum+=i
print(sum)

add(2,7,5)

 

-------------------------------------------------------

补全

 

import time

def cal_time(func):

def inter(*args, **kwargs):
t1 = time.time()
result = func(*args, **kwargs)
t2 = time.time()
print("%s time: %s" % (func.__name__, t2 - t1))
return result

return inter

@cal_time
def add(x, y):
return x + y

当使用一个装饰器时,打印函数名会出现问题

print(add.__name__)
##输出
inter

使用标准库里的

functools.wraps
,可以基本解决这个问题

看的别人写的文章说是拿不到数字签名等信息,但是在Python3.5里面可以拿到

可以使用wrapt包来进行修正

Wrapt

需要安装

pip install wrapt

wrapt是一个功能非常完善的包,用于实现各种你想到或者你没想到的装饰器。使用wrapt实现的装饰器你不需要担心之前inspect中遇到的所有问题,因为它都帮你处理了,甚至

inspect.getsource(func)
也准确无误。

import wrapt

@wrapt.decorator
def cal_time(func, instance, args, kwargs):
t1 = time.time()
result = func(*args, **kwargs)
t2 = time.time()
print("%s time: %s" % (func.__name__, t2 - t1))
return result

@cal_time
def add(x, y):
return x + y

使用wrapt你只需要定义一个装饰器函数,但是函数签名是固定的,必须是

(wrapped, instance, args, kwargs)
,注意第二个参数
instance
是必须的,就算你不用它。当装饰器装饰在不同位置时它将得到不同的值,比如装饰在类实例方法时你可以拿到这个类实例。根据
instance
的值你能够更加灵活的调整你的装饰器。另外,
args
kwargs
也是固定的,注意前面没有星号。在装饰器内部调用原函数时才带星号。

如果你需要使用wrapt写一个带参数的装饰器,可以这样写。

 
def logging(level):
@wrapt.decorator
def wrapper(wrapped, instance, args, kwargs):
print("[{}]: enter {}()".format(level, wrapped.__name__))
return wrapped(*args, **kwargs)
return wrapper

@logging(level="INFO")
def do(work): pass

类装饰器及更多内容

详解Python的装饰器

Python装饰器的另类用法

wrapt文档

  

  

  

 

转载于:https://www.cnblogs.com/bw13/p/5850367.html

  • 点赞
  • 收藏
  • 分享
  • 文章举报
dengdieli5313 发布了0 篇原创文章 · 获赞 0 · 访问量 125 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: