前言

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

很多python初学者学到面向对象类和方法是一道大坎,那么python中的装饰器是你进入Python高级语法大门的一道坎。

计算函数运行时间

假设你写了几个函数,有一天领导心血来潮说,你把每个函数的运行时长(结束时间-开始时间)统计下,作为一个python实习生的你可能会这样写

原始函数

import time

def func_a():
print("hello")
time.sleep(0.5) def func_b():
print("world")
time.sleep(0.8) if __name__ == '__main__':
func_a()
func_b()

添加运行时长

作为一个实习生的你,可能想到的解决办法如下

import time

def func_a():
start = time.time()
print("hello")
time.sleep(0.5)
end = time.time()
print("运行时长:%.4f 秒" % (end-start)) def func_b():
start = time.time()
print("world")
time.sleep(0.8)
end = time.time()
print("运行时长:%.4f 秒" % (end-start)) if __name__ == '__main__':
func_a()
func_b()

运行结果:

hello
运行时长:0.5009 秒
world
运行时长:0.8008 秒

上面的代码虽然满足了领导的要求,但是如果你写的函数很多的话,每个函数都这样去添加,会显得代码很臃肿,有很多重复代码。

有一天你边上的一个python老司机看了下你的代码,给你指了条路:装饰器

函数装饰器

装饰器可以写成函数式装饰器,也可以写成一个类装饰器,先从简单的函数装饰器开始学习。

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

runtime函数就是一个装饰器了,它对原函数做了包装并返回了另外一个函数,额外添加了一些功能。在函数上方使用@语法糖就可以调用这个装饰器了

import time

def runtime(func):
def wrapper():
start = time.time()
f = func() # 原函数
end = time.time()
print("运行时长:%.4f 秒" % (end-start))
return f
return wrapper @runtime
def func_a():
print("hello")
time.sleep(0.5) @runtime
def func_b():
print("world")
time.sleep(0.8) if __name__ == '__main__':
func_a()
func_b()

运行结果

hello
运行时长:0.5001 秒
world
运行时长:0.8001 秒

函数带参数装饰器

上面的runtime就是一个简单的装饰器模型了,但并不强壮,如果函数里面带有参数,那就不管用了,并且函数的参数是不固定的,这时候就需要用到*args,**kwargs两兄弟了

import time

def runtime(func):
def wrapper(*args, **kwargs):
start = time.time()
f = func(*args, **kwargs) # 原函数
end = time.time()
print("运行时长:%.4f 秒" % (end-start))
return f
return wrapper @runtime
def func_a(a):
print("hello"+a)
time.sleep(0.5) @runtime
def func_b(b, c="xx"):
print("world"+b+c)
time.sleep(0.8) if __name__ == '__main__':
func_a("a")
func_b("b", c="xxx")

类装饰器

关于__call__方法,不得不先提到一个概念,就是可调用对象(callable),我们平时自定义的函数、内置函数和类都属于可调用对象,

但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable。

如果在类中实现了__call__方法,那么实例对象也将成为一个可调用对象

import time

class runtime(object):
def __init__(self, func):
self.func = func def __call__(self, *args, **kwargs):
start = time.time()
f = self.func(*args, **kwargs) # 原函数
end = time.time()
print("运行时长:%.4f 秒" % (end-start))
return f @runtime
def func_a(a):
print("hello"+a)
time.sleep(0.5) @runtime
def func_b(b, c="xx"):
print("world"+b+c)
time.sleep(0.8) if __name__ == '__main__':
func_a("a")
func_b("b", c="xxx")

装饰器带参数

快到年底了,领导说运行的速度先不要太快了,让客户先加钱,然后再以正常的速度显示,那么现在的需求是让每个函数的运行时间加50%,该如何实现呢?

这就到了装饰器的高级语法,装饰器也需要带上参数了

函数装饰器

import time

def runtime(slowly=1):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
start = time.time()
f = func(*args, **kwargs) # 原函数
end = time.time()
t = end-start
time.sleep((slowly-1)*t) # 延迟效果
new_end = time.time()
print("运行时长:%.4f 秒" % (new_end-start))
return f
return inner_wrapper
return wrapper @runtime(1.5)
def func_a(a):
print("hello"+a)
time.sleep(0.5) @runtime(1.5)
def func_b(b, c="xx"):
print("world"+b+c)
time.sleep(0.8) if __name__ == '__main__':
func_a("a")
func_b("b", c="xxx")

类装饰器

import time

class runtime(object):
def __init__(self, slowly=1):
self.slowly = slowly def __call__(self, func):
def wrapper(*args, **kwargs):
start = time.time()
f = func(*args, **kwargs) # 原函数
end = time.time()
t = end-start
time.sleep((self.slowly-1)*t) # 延迟效果
new_end = time.time()
print("运行时长:%.4f 秒" % (new_end-start))
return f
return wrapper @runtime(1.5)
def func_a(a):
print("hello"+a)
time.sleep(0.5) @runtime(1.5)
def func_b(b, c="xx"):
print("world"+b+c)
time.sleep(0.8) if __name__ == '__main__':
func_a("a")
func_b("b", c="xxx")

使用场景

用哪些地方需要使用装饰器呢?

  • 如果你用过locust,设置权重会用到@task(1),
  • 如果你用过pytest框架,使用fixture功能的时候经常会用到@pytest.fixture(scope="function")
  • allure里面可以添加测试步骤 @allure.step('修改购物车')
  • 被大量使用于Flask和Django web框架中,检查是否被授权去使用一个web应用的端点(endpoint)。如 @login_required
  • 也可以自己写个装饰器添加日志

python自动化交流 QQ群:779429633

python笔记35-装饰器的更多相关文章

  1. python笔记 - day4-之装饰器

                 python笔记 - day4-之装饰器 需求: 给f1~f100增加个log: def outer(): #定义增加的log print("log") ...

  2. Python笔记:装饰器

    装饰器        1.特点:装饰器的作用就是为已存在的对象添加额外的功能,特点在于不用改变原先的代码即可扩展功能: 2.使用:装饰器其实也是一个函数,加上@符号后放在另一个函数“头上”就实现了装饰 ...

  3. 20.python笔记之装饰器

    装饰器 装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作. 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插 ...

  4. Noah的学习笔记之Python篇:装饰器

    Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang  (http://www.cnblogs.com/noahzn/) ...

  5. Python学习笔记:装饰器

    Python 装饰器的基本概念和应用 代码编写要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即: 封闭:已 ...

  6. Python函数06/装饰器

    Python函数06/装饰器 目录 Python函数06/装饰器 内容大纲 1.装饰器 1.1 开放封闭原则 1.2 装饰器 2.今日练习 内容大纲 1.装饰器 1.装饰器 1.1 开放封闭原则 扩展 ...

  7. python高级之装饰器

    python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函数的定义: 满足下面两个条件之 ...

  8. [python基础]关于装饰器

    在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...

  9. Python深入05 装饰器

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法 ...

  10. Day04 - Python 迭代器、装饰器、软件开发规范

    1. 列表生成式 实现对列表中每个数值都加一 第一种,使用for循环,取列表中的值,值加一后,添加到一空列表中,并将新列表赋值给原列表 >>> a = [0, 1, 2, 3, 4, ...

随机推荐

  1. python:字符串中提取特定的数据

    在日志文件中有一大堆,格式相同的文本,需要提取出接口耗时的时间 >>> 运单号:71742507538566,快递100接口耗时:8,返回结果:[{"lengthPre&q ...

  2. Python Number(数字)

    Python Number 数据类型用于存储数值. 数据类型是不允许改变的,这就意味着如果改变 Number 数据类型的值,将重新分配内存空间. 以下实例在变量赋值时 Number 对象将被创建: A ...

  3. WEUI Search Input回车键无法跳转解决

    现象:回车键依然当前页面, window.location.href 设置无法起作用 增加 window.event.returnValue = false; 解决问题

  4. Delphi TButton.OnClick 匿名函数用法

    type TNotifyEventRef = reference to procedure(Sender: TObject); function AnonymousEvent(const Proc: ...

  5. Python之路【第九篇】:Python面向对象

    阅读目录 一.三大编程范式 编程范式即编程的方法论,标识一种编程风格: 大家学习了基本的python语法后,大家可以写python代码了,然后每个人写代码的风格不同,这些不同的风格就代表了不同的流派: ...

  6. S02_CH12_ AXI_Lite 总线详解

    S02_CH12_ AXI_Lite 总线详解 12.1前言 ZYNQ拥有ARM+FPGA这个神奇的架构,那么ARM和FPGA究竟是如何进行通信的呢?本章通过剖析AXI总线源码,来一探其中的秘密. 1 ...

  7. Visual Studio 2019激活

    Visual Studio 2019 Enterprise BF8Y8-GN2QH-T84XB-QVY3B-RC4DF Visual Studio 2019 Professional NYWVH-HT ...

  8. 【EBS】XLA_GLT表的清理

    一.Xla_glt*在出现在日记账导入中的阶段 与R11使用gl_interface表不同,R12中大部分情况下使用的是XLA_GLT_<groupId>表:子帐传送到总账的过程中,会动态 ...

  9. CDN 访问控制的那些事

    网络已经成为生活中必不可少的一部分,无论是清早手机翻看的新闻八卦,还是公交地铁里刷的停不下来的短视频,又或是你闲逛的购物网站,热追的电视剧,都与 CDN 有着密不可分的联系.无论你在互联网上做什么,或 ...

  10. [cf 1245 F] Daniel and Spring Cleaning

    题意: 求区间$[l,r]$内有多少有序数对$(a,b)$满足$a+b=a\bigoplus b$. $l,r\leq 10^9$. 题解: 有用的就一句话: 求区间内一元组可以一维容斥,同理求二元组 ...