首页 > 技术文章 > python-装饰器

wang-mengmeng 2019-07-26 17:51 原文

 使用实例:

背景:测试过程中,遇到这样一种情况,A接口请求后需要等待几秒再执行B接口请求,可以给B加个装饰器实现此功能,让B每次请求时先等待几秒。

example1:

import time
def wait(func):
    # func(*args, **kw)可以使函数适配任意多的参数
    def wrapper(*args, **kw):
        time.sleep(3)
        return func(*args, **kw)

    return wrapper

class Template: @wait def get_opt_auditresult(self, engineid, type): # time.sleep(4) @wait实现了该功能 url = '' if type == 1: url = self.conf.get('auditcenter', 'address') + '/api/v1/opt/all /auditResultList/' + str(engineid) return self.get(url) # 调用 from common.template_2_x import Template from config.read_config import ReadConfig import unittest import warnings class TestDelete(unittest.TestCase): def setUp(self): warnings.simplefilter("ignore", ResourceWarning) self.tem = Template() def test_opt_07(self): '''审核通过,医生修改处方''' engineid = self.tem.get_opt_engineid('opt','处方一',1) # 审核打回 self.tem.opt_audit(engineid,0) self.tem.send_data('opt','修改处方一1',**self.tem.change_data) # 只修改处方头 res = self.tem.get_opt_auditresult(engineid,1) self.assertEqual(2,res['data'][0]['rejectStatus']) if __name__ == '__main__': unittest.main()

 实例代码地址:传送门

example2:

def dec(f):
    n = 3
    def wrapper(*args,**kw):
        return f(*args,**kw) * n
    return wrapper

@dec
def foo(n):
    return n * 2

foo(2)

相当于:
def dec(f):
    n = 3
    def wrapper(*args,**kw):
        return f(*args,**kw) * n
    return wrapper


def foo(n):
    return n * 2

foo=dec(foo)
foo(2)
code

简言之,foo(2)=wrapper(2)=foo(2)*3=2*2*3=12

装饰器理论介绍

装饰器是什么:

装饰器是为已经存在的函数或者对象添加额外的功能。本质上是一个闭包函数(闭包函数:本质是个嵌套函数,内层函数引用外层函数的变量,外层函数返回内层函数)

装饰器的作用:

1.不修改已有函数的源代码

2.不修改已有函数的调用方式

3.为已有函数添加额外的功能

格式一:有参数

@decorator(arg1, arg2)    
def fun():
    pass

等价于:
def fun():
    pass
fun = decorator(arg1, arg2)(fun)

格式二:无参数

import time
from functools import wraps


def timethis(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(func.__name__, end - start)
return result

return wrapper


@timethis
def conutdown(n):
while n > 0:
n -= 1
"""
@timethis
def conutdown(n):
while n > 0:
n -= 1
等价于 conutdown = timethis(conutdown) 该装饰器代码本身就会运行,而不是等到conutdown(10000)才执行,理解不了的话,在@timethis处打个断点debug一下就知道怎么执行的了
执行过程为:
调用timethis,返回wrapper,且conutdown指向wrapper,所以后面执行conutdown(10000)就相当与执行wrapper(10000)
"""

conutdown(10000)
print(conutdown.__name__)
输出结果为:

  conutdown 0.015621423721313477
  conutdown      # 注意红色字体@wraps(fun1)是为了避免被装饰函数自身的信息丢失,如果注释@wraps(fun1),该输出结果将会是wrapper,故任何时候定义装饰器的时候,都应该使用 functools 库中的 @wraps 装饰器来注解底层包装函数

格式三:有多个装饰器

@decotator_one
@decorator_two
def fun():
 pass

等价于:
def fun():
 pass
fun = decorator_one(decorator_two(fun) 

三大内置装饰器(@staticmethod、@classmethod、@property)

静态方法:是类中的方法,不需要实例。 需要通过修饰器 @staticmethod 来进⾏修饰,静态⽅法不需要多定义参数

  • 特性:静态方法不能使用类变量和实例变量
  • 调用方式:一般通过类名调用

类方法:是类对象所拥有的⽅法,需要⽤修饰器 @classmethod 来标识其为类⽅法,对于类⽅法,第⼀个参数必须是类对象,⼀般以 cls 作为第⼀个参数(当然可以⽤其他名称的变量作为其第⼀个参数,但是⼤部分⼈都习惯以'cls'作为第⼀个参数的名字,就最好⽤'cls'了),能够通过实例对象和类对象去访问

  •  特性:只能访问类变量,不能访问实例变量
  • 调用方式:通过实例对象或类对象去访问

 

 

推荐阅读