1、Python装饰器简介
python的装饰器就是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。简单的说装饰器就是一个用来返回函数的函数。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题,代码很好地重用。简单理解,装饰器的作用就是为已经存在的对象添加额外的功能。
2、Python内置装饰器
相关文档:Python内置装饰器(@property、@staticmethod、@classmethod)使用及示例代码
3、Python装饰器语法及原理
python提供了@
符号作为装饰器的语法糖,使我们更方便的应用装饰函数。但使用语法糖要求装饰函数必须return
一个函数对象。因此我们将上面的func
函数使用内嵌函数包裹并return
。
装饰器相当于执行了装饰函数use_loggin
后又返回被装饰函数bar,因此bar()
被调用的时候相当于执行了两个函数。等价于use_logging(bar)()
def use_logging(func): def _deco(): print("%s is running" % func.__name__) func() return _deco @use_logging def bar(): print('i am bar') bar()
4、Python装饰器的使用
1)装饰器修饰带参数方法
def use_logging(func):
def _deco(a,b):
print("%s is running" % func.__name__)
func(a,b)
return _deco
@use_logging
def bar(a,b):
print('i am bar:%s'%(a+b))
bar(1,2)
2)装饰器修饰不确定参数个数方法
def use_logging(func):
def _deco(*args,**kwargs):
print("%s is running" % func.__name__)
func(*args,**kwargs)
return _deco
@use_logging
def bar(a,b):
print('i am bar:%s'%(a+b))
@use_logging
def foo(a,b,c):
print('i am bar:%s'%(a+b+c))
bar(1,2)
foo(1,2,3)
3)带参数的装饰器
#! /usr/bin/env python # -*- coding:utf-8 -*- # __author__ = "TKQ" def use_logging(level): def _deco(func): def __deco(*args, **kwargs): if level == "warn": print "%s is running" % func.__name__ return func(*args, **kwargs) return __deco return _deco @use_logging(level="warn") def bar(a,b): print('i am bar:%s'%(a+b)) bar(1,3) # 等价于use_logging(level="warn")(bar)(1,3)
4)使用functools.wraps解决原函数的元信息问题
import functools def use_logging(func): @functools.wraps(func) def _deco(*args,**kwargs): print("%s is running" % func.__name__) func(*args,**kwargs) return _deco @use_logging def bar(): print('i am bar') print(bar.__name__) bar() #result: #bar is running #i am bar #bar
5、装饰器同时兼容带参数和不带参数的情况
import functools def use_logging(arg): if callable(arg):#判断传入的参数是否是函数,不带参数的装饰器调用这个分支 @functools.wraps(arg) def _deco(*args,**kwargs): print("%s is running" % arg.__name__) arg(*args,**kwargs) return _deco else:#带参数的装饰器调用这个分支 def _deco(func): @functools.wraps(func) def __deco(*args, **kwargs): if arg == "warn": print "warn%s is running" % func.__name__ return func(*args, **kwargs) return __deco return _deco @use_logging("warn") # @use_logging def bar(): print('i am bar') print(bar.__name__) bar()
6、类的装饰器的使用
class loging(object): def __init__(self,level="warn"): self.level = level def __call__(self,func): @functools.wraps(func) def _deco(*args, **kwargs): if self.level == "warn": self.notify(func) return func(*args, **kwargs) return _deco def notify(self,func): # logit只打日志,不做别的 print "%s is running" % func.__name__ @loging(level="warn")#执行__call__方法 def bar(a,b): print('i am bar:%s'%(a+b)) bar(1,3) #继承扩展类的装饰器 class email_loging(Loging): ''' 一个loging的实现版本,可以在函数调用时发送email给管理员 ''' def __init__(self, email='admin@myproject.com', *args, **kwargs): self.email = email super(email_loging, self).__init__(*args, **kwargs) def notify(self,func): # 发送一封email到self.email print "%s is running" % func.__name__ print "sending email to %s" %self.email @email_loging(level="warn") def bar(a,b): print('i am bar:%s'%(a+b)) bar(1,3)