首页 > 技术文章 > 装饰器

Teyisang 2020-07-30 19:15 原文

一、什么是装饰器?

器 就是工具 可以用函数定义

装饰 为其他事物添加功能

合到一起可以理解成是定义一个函数来装饰其他函数。给其他函数添加额外的功能。

装饰器 的使用满足开放封闭原则

即对于代码功能的拓展是开放的

对于修改源代码是封闭的

合到一起就是不能改函数的调用方式,和原函数的代码,但是要增加原函数的功能。

二、装饰器怎么定义?

from functools import wraps

 

def outter(func):

  @wraps(func)   # 将wrapper函数伪装成func函数的工具,除了返回值,参数以外,包括func的内置属性__name__,__file__等等都伪装成一样的。

  def wrapper(*args,**kwargs):  # 确保wrapper的参数,返回值,调用方式都跟func一模一样,但是可以增加一些功能

    # 功能可以增加在这里

    res = func(*args,**kwargs)

    return res

  return wrapper

==============================>  下面是函数的调用阶段啦

func = outter(func)  # 返回值就是wrapper函数的内存地址,之后再加上括号就可以实现在不改变func函数的代用方式,和代码的情况下,实现对于func功能的增加。这就是无参装饰器的模板啦!

python给我们提供了语法糖,准许我们将func = outter(func) 这样的语句,简写成

@outter  # 在被装饰的函数上面声明装饰器即可实现为函数加上功能,可以制作一些认证装饰器,时间装饰器,等等

def func(*args,**kwargs):

  pass

 

==================================================》 下面是有参装饰器啦~

from functools import wraps

def code(x):

  def outter(func):

    @wraps(func)

    def wrapper(*args,**kwargs):  # 确保wrapper的参数,返回值,调用方式都跟func一模一样,但是可以增加一些功能

      # 功能可以增加在这里

      res = func(*args,**kwargs)

      return res

    return wrapper

  return outter

==============================>  下面是函数的调用阶段啦

受语法糖的限制,我们不能再outter函数中在增加参数了,但是如果确实还有需要传进来的变量参数呢,我们可以通过再嵌套一层的方法给函数传参。

outter = code(x)

无参装饰器时语法糖是 将 func = outter(func)  ---> 简化成 ---> @outter

现在outter 就是 code(x) -----------------------------------------------> @code(x)  这就是有参的装饰器啦~,这里传X只是一个例子,其实可以传不限的参数。

 

三、如何使用装饰器

1.定义一个计算函数运行时间的装饰器

from functools import wraps

import time

 

def timmer(func):

  @wraps(func)

  def wrapper(*args,**kwargs):  # 确保wrapper的参数,返回值,调用方式都跟func一模一样,但是可以增加一些功能

    # 功能可以增加在这里

    start = time.time

    res = func(*args,**kwargs)

    end = time.time

    print(f‘执行函数用时start-end秒’)

    return res

  return wrapper

  

2.定义一个认证功能的装饰器

from functools import wraps

 

def auth(func):

  @wraps(func)

  def wrapper(*args,**kwargs):  # 确保wrapper的参数,返回值,调用方式都跟func一模一样,但是可以增加一些功能

    # 功能可以增加在这里

    user_name = input('用户名>>>:‘)

    psd = input('密码>>>:')

    # 从文件查找用户名和密码认证

    f = open('a.txt')

    for line in f:

      if user_name.split().lower() in line.lower and psd in line:

        res = func(*args,**kwargs)

        return res

      else:

        print('登录失败')

  return wrapper

 

四、多层装饰器的套用

如果一个函数上面套用了很多个装饰器

@auth

@timmer

@...

def func():

  pass

 

需要从内向外一层层使用装饰器功能,从函数开始,函数上面一层层剥开装饰器。

推荐阅读