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


猜你喜欢
- 先看看效果:效果-点击弹出弹框 -点击复选框,已选div中 显示已选中的选项 -再次点击取消选中状态,已选div中 显示的选中选项取消显示
- 1.双摆问题所谓双摆,就是两个连在一起的摆。接下来本来是要推公式的,考虑考虑到大家可能会有公式恐惧症,同时又喜欢看图,所以把公式挪到后面。所
- MySQL中的事件调度器,EVENT,也叫定时任务,类似于Unix crontab或Windows任务调度程序。EVENT由其名称和所在的s
- Sql Server为每个触发器都创建了两个专用表:Inserted表和Deleted表。这两个表由系统来维护,它们存在于内存中
- axios库的 * 使用我们知道axios库的 * 的使用方式如下:// 添加一个请求 * axios.interceptors.reque
- 以前讲过利用phantomjs做爬虫抓网页 https://www.jb51.net/article/55789.htm 是配合选择器做的利
- 1. 监测端口我们要引用的socket模块来校验端口是否被占用。1.1 socket是什么?简单一句话:网络上的两个程序通过一个双向的通信连
- 一、编写Python脚本[root@lidabai ~]# vim harbor_clearimage.py# -*- coding:utf
- isset(PHP 3, PHP 4, PHP 5 )isset -- 检测变量是否设置描述bool isset ( mixed var [
- 今天终于可以用wxPython开发GUI程序了,非常高兴。把其中的一些注意点写下来以供参考。在windows XP平台下,首先需要做以下环境
- JavaScript闭包,是JS开发工程师必须深入了解的知识。3月份自己曾撰写博客《JavaScript闭包》,博客中只是简单阐述了闭包的工
- 说到运维报警,我觉得都可以写个长篇历史来详细解释了报警的前世来生,比如最早报警都是用邮件,但邮件实时性不高,比如下班回家总不能人一直盯着邮箱
- 1. python中数字组成的列表转化为字符串或者一串数字f=[1,2,3,4]num=len(f)m='' #
- 注册了oracle的登录名:10402852@qq.com密码:dsideal******** 后面的*号是王卓常用的密码,但是
- print只是为了向用户显示一个字符串,表示计算机内部正在发生的事情。计算机却无法使用该print出现的内容。return是函数的返回值。该
- modelform是model衍生出来的form .modelform的用法非常死.首先在models.py里创建模型表.所有的form组件
- javascript动画效果 打开层/关闭层:运行代码框<!DOCTYPE html PUBLIC "-//W3C//DTD
- 使用python实现文件导入,具体方法如下:文件样例可以自己random这里的temp1根据每一行的分隔符来读入,‘\n'表述回车t
- Python之Web框架Django项目搭建全过程IDE说明:Win7系统Python:3.5Django:1.10Pymysql:0.7.
- 我们将在下面的例子中使用这个 XML 文档。<?xml version="1.0" encod