python装饰器

 

参考:

https://www.runoob.com/w3cnote/python-func-decorators.html

https://www.jb51.net/article/240440.htm

用途:定义一个函数,来修饰之前老的代码,以便在不修改原代码的情况下增加新功能

关键原理:把函数作为参数,函数后面不加()就可以随意传递,加了()函数就会执行

一. 第一个装饰器例子

1.基本功能实现
def deco(func):
  def inner():
    print("something before hi")
    func()
    print("something after hi")
  return inner
​
def hi():
  print("hi")
​
hi=deco(hi)
hi()
这正是 python 中装饰器做的事情!它们封装一个函数,并且用这样或者那样的方式来修改它的行为
2.现在用符号@来修改上面代码
def deco(func):
  def inner():
    print("something before hi")
    func()
    print("something after hi")
  return inner
​
@deco
def hi():
  print("hi")
​
hi()
print(hi.__name__) //输出为inner

@deco其实就相当于hi=deco(hi)

不过现在最后一个行输出为inner, 我们想把它输出为hi,应该怎么做呢?

幸运的是Python提供给我们一个简单的函数来解决这个问题,那就是functools.wraps

3. functools.wraps改写
from functools import wraps
​
def deco(func):
  @wraps(func)
  def inner():
    print("something before hi")
    func()
    print("something after hi")
  return inner
​
@deco
def hi():
  print("hi")
​
hi()
print(hi.__name__) //输出为hi

@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

 

二. 带参数的装饰器

from functools import wraps
import time
​
def delay_deco(delay=0):
  def deco(func):
    @wraps(func)
    def inner():
      print("something before hi")
      time1 = time.time()
      time.sleep(delay)
      time2 = time.time()
      func()
      print("something after hi")
      print("耗时:{:.8f}".format(time2-time1))
    return inner
  return deco
​
@delay_deco(2.0)
def hi():
  print("hi")
​
hi()
print(hi.__name__) 

其实就是在原先的基础上,再加一层嵌套。上面代码实现延迟2秒执行,参数就是延迟的时间

 

三. 类装饰器

装饰器本身既可以是函数也可以是类,装饰的对象同样可以是函数也可以是类。

1. 最简单的例子
class Deco:
  def __init__(self, func):
    self._func = func
​
  def __call__(self, *args, **kwargs): #定义__call__函数,让类实例成为可调用对象
    print("类装饰器")
    return self._func(*args, **kwargs)
​
@Deco
def test():
  print("被装饰函数")
​
test()
例子2:根据例子1,稍微复杂点,被装饰的函数中添加参数
import time
​
class Deco:
  def __init__(self, func):
    self.func = func
​
  def __call__(self, *args, **kwargs):
    start = time.time()
    ret = self.func(*args, **kwargs)
    print(f'Time: {time.time()-start}')
    return ret
​
@Deco
def add(a,b):
  time.sleep(1)
  return a+b
​
print(add(3,4))
这个装饰器,相当于把一个装饰器变成了一个Deco类的对象,然后add被传入进了init中,保存为self.func
在后面调用add(3,4)的时候,实际上相当于调用了call这个函数,做了一个对象的调用,后面参数3和4就被传入到了call里面,然后依顺序运行了代码。
例子3:带参数的类装饰器
import time
​
class Deco:
  def __init__(self, prefix):
    self.prefix = prefix
    
  def __call__(self, func):
    def inner(*args, **kwargs):
      start = time.time()
      ret = func(*args, **kwargs)
      print(f'{self.prefix}: {time.time()-start}')
      return ret
    return inner
​
@Deco(prefix='current_time')
def add(a,b):
  time.sleep(1)
  return a+b
​
print(add(3,4))

我们把参数写入init函数中,相当于先实例化了一个Deco对象,call函数内做一个嵌套,类似于函数装饰器

 

posted @ 2022-10-18 14:06  坚强的小蚂蚁  阅读(38)  评论(0编辑  收藏  举报