Python装饰器(decorator)定义与用法详解
作者:初心不忘 发布时间:2022-07-21 03:11:25
本文实例讲述了Python装饰器(decorator)定义与用法。分享给大家供大家参考,具体如下:
什么是装饰器(decorator)
简单来说,可以把装饰器理解为一个包装函数的函数,它一般将传入的函数或者是类做一定的处理,返回修改之后的对象.所以,我们能够在不修改原函数的基础上,在执行原函数前后执行别的代码.比较常用的场景有日志插入,事务处理等.
装饰器
最简单的函数,返回两个数的和
def calc_add(a, b):
return a + b
calc_add(1, 2)
但是现在又有新的需求,计算求和操作耗时,很简单,求和前获取一下时间,求和后再获取一次,求差即可
import datetime
def calc_add(a, b):
start_time = datetime.datetime.now()
result = a + b
end_tiem = datetime.datetime.now()
print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
return result
calc_add(1, 2)
现在呢,函数calc_diff(a, b)
,计算a-b,也想计算减法操作的时间差,很好办,把那段代码复制过去.但是假如我们现在想编的是一个数学函数库,各种函数都想计算其执行耗时,总不能一个一个复制代码,想个更好的办法.
我们知道,在Python中函数也是被视为对象的,可以作为参数传递,那么假如把计算耗时的独立为一个单独的函数calc_spend_time()
,然后把需要计算耗时的函数例如calc_add的引用传递给它,在calc_spend_time中调用calc_add,这样所有的需要计算耗时的函数都不用修改自己的代码了.
def calc_spend_time(func, *args, **kargs):
start_time = datetime.datetime.now()
result = func(*args, **kargs)
end_tiem = datetime.datetime.now()
print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
def calc_add(a, b):
return a + b
calc_spend_time(calc_add, 1, 1)
# calc_spend_time(calc_add, a=1, b=2)
看起来也不错,负责计算的函数不用更改,只需调用的时候作为参数传给计算时间差的函数.但就是这,调用的时候形式变了,不再是clac(1, 2),而是calc_spend_time(clac_add, 1, 2),万一calc_add大规模被调用,那么还得一处一处找,然后修改过来,还是很麻烦.如果想不修改代码,就得使clac()
和calc_spend_time(clac)
效果一样,那么可以在calc_spend_time()
里把传入的clac包装一下,然后返回包装后的新的函数,再把返回的包装好的函数赋给clac,那么calc()的效果就和上例calc_spend_time(calc())
效果一样.
import datetime
def calc_spend_time(func):
def new_func(a, b):
start_time = datetime.datetime.now()
result = func(a, b)
end_tiem = datetime.datetime.now()
print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
return new_func
def calc_add(a, b):
return a + b
calc_add = calc_spend_time(calc_add)
calc_add(1, 2)
语法糖
上面的例子就是装饰器的概念,包装函数的函数.事实上上面的例子还可以更精简
import datetime
def calc_spend_time(func):
def new_func(a, b):
start_time = datetime.datetime.now()
result = func(a, b)
end_tiem = datetime.datetime.now()
print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
return new_func
@calc_spend_time
def calc_add(a, b):
return a + b
calc_add(1, 2)
@calc_spend_time
就是语法糖,它的本质就是:calc_add = calc_spend_time(calc_add)
无参数的函数装饰器
import datetime
def calc_spend_time(func):
def new_func(*args, **kargs):
start_time = datetime.datetime.now()
result = func(*args, **kargs)
end_tiem = datetime.datetime.now()
print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
return new_func
@calc_spend_time
def calc_add(a, b):
return a + b
@calc_spend_time
def calc_diff(a, b):
return a - b
calc_add(a=1, b=2)
calc_diff(1, 2)
注:
*args:把所有的参数按出现顺序打包成list
**kargs:把所有的key=value形式的参数打包成一个dict
带参数的函数装饰器
假如我们需要知道函数的一些额外信息,例如函数作者,可以通过给装饰器函数增加参数来实现.
import datetime
def calc_spend_time(author):
def first_deco(func):
def new_func(*args, **kargs):
start_time = datetime.datetime.now()
result = func(*args, **kargs)
end_tiem = datetime.datetime.now()
print author, "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
return new_func
return first_deco
@calc_spend_time('author_1')
def calc_add(a, b):
return a + b
@calc_spend_time('author_2')
def calc_diff(a, b):
return a - b
calc_add(a=1, b=2)
calc_diff(1, 2)
Python内置装饰器
Python内置的装饰器有三个:staticmethod,classmethod和property.
staticmethod:把类中的方法定义为静态方法,使用staticmethod装饰的方法可以使用类或者类的实例对象来调用,不需要传入self
class Human(object):
"""docstring for Human"""
def __init__(self):
super(Human, self).__init__()
@staticmethod
def say(message):
if not message:
message = 'hello'
print 'I say %s' % message
def speak(self, message):
self.say(message)
Human.say(None)
human = Human()
human.speak('hi')
输出:
I say hello
I say hi
classmethod:把类中的方法定义为类方法,使用classmethod装饰的方法可以使用类或者类的实例对象来调用,并将该class对象隐式的作为第一个参数传入
class Human(object):
"""docstring for Human"""
def __init__(self):
super(Human, self).__init__()
self.message = '111'
def say(message):
if not message:
message = 'hello'
print 'I say %s' % message
@classmethod
def speak(cls, message):
if not message:
message = 'hello'
cls.say(message)
human = Human()
human.speak('hi')
输出同上例
property:把方法变成属性
class Human(object):
"""docstring for Human"""
def __init__(self, value):
super(Human, self).__init__()
self._age = value
@property
def age(self):
return self._age
human = Human(20)
print human.age
希望本文所述对大家Python程序设计有所帮助。
来源:http://blog.csdn.net/shuaijiasanshao/article/details/51381493
猜你喜欢
- 带农历的JavaScript日期时间,增加了农历使这款代码更具实用性,很不错,不但有农历,而且还可以显示民国计年,可以判断显示闰月、闰年等,
- 获取图片宽度和高度的类,支持JPG,GIF,PNG,BMP我们可以使用这个类来处理图片的显示。<% Class
- 有的时候,一个 if … else … 还不够用。比如,根据年龄的划分:条件1:18岁或以上:adult条件2:6岁或以上:teenager
- 今天在工作中遇到了一个问题,需要按时间查询,可是查询出来的结果显示的不正确。举个例子来说,要查找出2007-10-12至2007-10-31
- 有些时候(如开发聊天程序),我们需要将将滚动条(scrollbar)保持在最底部,比如聊天窗口,最新发出和收到的信息要显示在最下方,如果要看
- 在本人看来,HTML 5是一个妥协方案,虽不激进,但更能推动技术的继续进步。没有命名空间,元素也不要求闭合(当然这并不是优点),浏览器也可以
- 从今天开始,我将全面的共享出我所能理解的所有WEB标准方面的知识放在这个“WEB标准能有多难?”的专栏里。当然由于振之的水平有限,所讲并非是
- 概述从今天开始, 小白我将带领大家一起来补充一下 数据库的知识.MySQL 安装下载地址:https://dev.mysql.com/dow
- 现在我们已经知道了,fixtures是一个非常强大的功能。那么有的时候,我们可能会写一个fixture,而这个fixture所有的测试函数都
- 图片人脸识别import cv2filepath = "img/xingye-1.png"img = cv2.imrea
- 本文实例讲解了php表单验证的实现方法,分享给大家供大家参考,具体内容如下1.PHP表单处理welcome.html<html>
- 你喜欢在博客文章中使用图片吗?是的,如果不是很麻烦的话,相信大家都不会介意放上几张漂亮的图片来点缀一下内容的,不过你的图片可能会导致下面的两
- 微软 Office 提供基于 COM 接口的编程。Python 通过 pywin32 可以方便地调用各组件。如果下载和安装 pywin32
- 准备软件:1. J2SDK(1.5.0): jdk-1_5_0-linux-i586-rpm.bin2. Apache(2.0.53): h
- 最近在无忧脚本混了一阵子,回复了一些贴子,自己却没有做出什么东东让大家看看,心里有些不安,于是写了下边的一点东西,本来应该发在类封装区的,考
- 很多设计师都会遇到这样的问题。一个产品会有很多种方式去包装,其中包括很多功能和很多体验。功能越多会被认为越实用,体验越好会被认为越方便。方便
- 本文从多个角度来讲解如何在Access数据库上如何上传并且显示上所上传图片。在 * 站制做过程中,需要上传图片、显示图片,上传的图片要能够保
- SQL Server 2005 和 2008 有几个关于高可用性的选项,如日志传输、副本和数据库镜像。所有这些技术都能够作为维护一个备用服务
- PIL 图像处理库PIL(Python Imaging Library) 是 Python 平台的图像处理标准库。不过 PIL 暂不支持 P
- 此文主要讲述的是SQL Server连接中经常出现的3个常见错误,以及对这三个错误的详细分析,如果你其心存好奇的话,以下的文章将会揭开它的神