Python基础第七天:装饰器

一,什么是装饰器

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

  装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景

二,装饰器的形成过程

  现在我有一个需求,我想让你测试这个函数的执行时间,在不改变这个函数代码的情况下:

  import time

  def func1():
      time.sleep(1)
      print('in func1')

  def timer(func):
      def inner():
          start = time.time()
          func()
          print(time.time() - start)
      return inner

  func1 = timer(func1)
  func1()
  in func1
  1.0000572204589844

  但是如果有多个函数,我都想让你测试他们的执行时间,你每次是不是都得func1 = timer(func1)?这样还是有点麻烦,因为这些函数的函数名可能是不相同,有func1,func2,graph,等等,所以更简单的方法,python给你提供了,那就是语法糖

  import time

  def timer(func):
      def inner():
          start = time.time()
          func()
          print(time.time() - start)
      return inner

  @timer   #==> func1 = timer(func1)
  def func1():
      time.sleep(1)
      print('in func1')
    
  func1()
  in func1
  1.0000574588775635

   刚刚我们讨论的装饰器都是装饰不带参数的函数,现在要装饰一个带参数的函数怎么办呢?

  import time

  def timer(func):
      def inner(name):
          start = time.time()
          func(name)
          print(time.time() - start)
      return inner

  @timer   #==> func1 = timer(func1)
  def func1(name):
      time.sleep(1)
      print('我的名字是,',name)

  func1('小红')
  我的名字是, 小红
  1.0000572204589844
  import time

  def timer(func):
      def inner(*args,**kwargs):
          start = time.time()
          func(*args,**kwargs)
          print(time.time() - start)
      return inner

  @timer   #==> func1 = timer(func1)
  def func1(name,hooby):
      time.sleep(1)
      print('我的名字是 %s,喜欢 %s' % (name,hooby))

  @timer   #==> func1 = timer(func1)
  def func2(name):
      time.sleep(1)
      print('我的名字是 %s' % (name))

  func2('小明')
  func1('小红','旅游')
  我的名字是 小明
  1.0000569820404053
  我的名字是 小红,喜欢 旅游
  1.0000574588775635

  上面的装饰器已经非常完美了,但是有我们正常情况下查看函数信息的方法在此处都会失效:

  def index():
      """这是一个主页信息"""
      print("from index")

  print(index.__doc__) #查看函数注释的方法
  print(index.__name__) #查看函数名的方法
  这是一个主页信息
  index

  如何解决呢?

  from functools import wraps

  def deco(func):
      @wraps(func)
      def wrapper(*args,**kwargs):
          return func(*args,**kwargs)
      return wrapper


  def index():
      """哈哈哈"""
      print("from index")

  print(index.__doc__)
  print(index.__name__)

三,开放封闭原则

  1、对扩展是开放的

    为什么要对扩展开放呢?

    我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能;

  2、对修改是封闭的

    为什么要对修改封闭呢?

    就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户;

  装饰器完美的遵循了这个开放封闭原则;

四,装饰器的主要功能和固定结构

def timer(func):
    def inner(*args,**kwargs):
        '''执行函数之前要做的'''
        re = func(*args,**kwargs)
        '''执行函数之后要做的'''
        return re
    return inner
from functools import wraps

def deco(func):
  @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

五,带参数的装饰器

  假如你有成千上万个函数使用了一个装饰器,现在你想把这些装饰器都取消掉,你要怎么做?

一个一个的取消掉? 没日没夜忙活3天...

  过两天你领导想通了,再让你加上...

def outer(flag):
    def timer(func):
        def inner(*args,**kwargs):
            if flag:
                print("执行函数之前要做的")

            re = func(*args,**kwargs)

            if flag:
                print("执行函数后要做的")

            return re
        return inner
    return timer

@outer(True) #@outer(True) = @timer
def func():
    print("1234567890")

func()
执行函数之前要做的
1234567890
执行函数后要做的

六,多个装饰器装饰一个函数

# 多个装饰器装饰同一个函数
# 有些时候,我们也会用到多个装饰器装饰同一个函数的情况。

def wrapper1(func):
    def inner():
        print('wrapper1 ,before func')
        func()
        print('wrapper1 ,after func')
    return inner

def wrapper2(func):
    def inner():
        print('wrapper2 ,before func')
        func()
        print('wrapper2 ,after func')
    return inner

@wrapper1
@wrapper2
def f():
    print('test ---------')

f()
wrapper1 ,before func
wrapper2 ,before func
test ---------
wrapper2 ,after func
wrapper1 ,after func
原文地址:https://www.cnblogs.com/nzd123456/p/8970331.html