装饰器也是一个函数,它可以在不改变任何代码的前提下增加额外功能。
日常使用场景:面向AOP编程中,比如:插入日志,性能测试,事务处理,缓存,权限校验。
函数装饰器
一个简单的装饰器
def write_to_log(func):
def inner(*args, **kwargs):
logging.warn("%s is running"%(func.__name__))
return func(*args, **kwargs)
return inner
@write_to_log
def a():
print('xxxx')
带有参数的装饰器
def write_to_log(level):
def decorator(func):
def inner(*args, **kwargs):
if level == "warn":
logging.warn("%s is running"%(func.__name__))
return func(*args, **args)
return inner
return decorator
@write_to_log(level='warn')
def a():
print("xxxx")
类装饰器
类装饰器优点
- 灵活度大
- 高内聚
- 封装性
- 可以调用类的__call__(),当使用@附加到函数上的时候调用此函数
class Decorator:
def __init__(self, func):
self.func = func
def __call__(self):
print("函数执行前的操作")
self.func()
print("函数执行后的操作")
@Decorator
def a():
print("xxxx")
当不使用@装修函数的时候会有元函数信息丢失的状况。
def logged(func):
def with_logging(*args, **kwargs):
print func.__name__
print func.__doc__
return func(*args, **kwargs)
return with_logging
def a():
print("xxxxx")
a = logged(a)
print(a.__name__)
print(a.__doc__)
======================================输出==========================
with_logging
None
对于这种情况应该使用functools中的wraps对内部函数进行装饰,这样就可以将元函数的信息拷贝到装饰器函数当中了。
from functools import wraps
def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print func.__name__
print func.__doc__
return func(*args, **kwargs)
return with_logging
def a():
print("xxxxx")
a = logged(a)
print(a.__name__)
print(a.__doc__)
===========================================输出========================================
a
None
装饰器执行顺序
@a
@b
@c
def f():
pass
====================>>>>>>>>>>>>>>>>>>>>等价于<<<<<<<<<<<<<<<<<<=================
a(b(c(f())))
内置装饰器
- @staticmethod
- @classmethod
- @property
@property 像调用类属性一样的方式来调用属性方法
class Stu:
def __init__(self, name):
self.name = name
@property
def say(self):
print("say my name is %s"%(self.name))
s = Stu('zhangsan')
s.say
==================================输出=====================================
say my name is zhangsan
@classmethod 装饰方法为类方法
class Stu:
def __init__(self, name):
self.name = name
@classmethod
def fuc(self):
print("i m class method")
Stu.fuc()
Stu('name').fuc()# 类方法也可以通过实例来调用,但是不建议这么用
@staticmethod 将类中的方法装饰为静态方法
class Stu:
def __init__(self, name):
self.name = name
@staticmethod
def fuc(self):
print("i m class method")
#调用静态方法时参数个数必须与静态方法中的参数个数一致
Stu.fuc(None)#通过类名来引用
Stu('name').fuc(None)# 静态方法也可以通过实例来调用
==================================输出==================================
i m class method
i m class method