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内置的装饰器有三个:staticmethodclassmethodproperty

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

标签:Python,装饰器,decorator
0
投稿

猜你喜欢

  • 混淆矩阵Confusion Matrix概念分析翻译

    2022-07-05 15:08:56
  • Python 使用requests模块发送GET和POST请求的实现代码

    2023-07-19 23:19:27
  • 巧用JDBC实现对MySQL的“增删改查”

    2008-12-31 15:12:00
  • ASP中如何判断字符串中是否包数字

    2008-07-21 12:04:00
  • Python使用numpy模块实现矩阵和列表的连接操作方法

    2023-02-17 21:05:41
  • python实现抠图给证件照换背景源码

    2022-06-21 04:39:38
  • D3.js实现拓扑图的示例代码

    2024-05-09 10:20:06
  • html元素input使用方法

    2007-12-06 13:02:00
  • 一文掌握MySQL表的创建和约束

    2024-01-25 18:36:53
  • Python创建7种不同的文件格式的方法总结

    2021-01-24 03:13:51
  • js特殊字符过滤的示例代码

    2023-09-07 21:53:30
  • sqlalchemy实现时间列自动更新教程

    2021-08-18 20:12:58
  • 2003年至今网页尺寸增长3倍

    2008-04-29 19:27:00
  • Python发起请求提示UnicodeEncodeError错误代码解决方法

    2022-09-14 09:47:36
  • asp如何在数据库中用好Transaction?

    2010-06-22 21:07:00
  • Pytorch统计参数网络参数数量方式

    2021-03-13 03:09:04
  • python两种获取剪贴板内容的方法

    2021-03-05 11:18:56
  • pygame学习笔记(4):声音控制

    2021-08-15 20:04:35
  • 关于keras多任务多loss回传的思考

    2023-09-16 18:58:47
  • 上传图片js判断图片尺寸和格式兼容IE

    2024-04-10 10:48:37
  • asp之家 网络编程 m.aspxhome.com