学习Java的都知道Java 中有面向切面的编程,也就是aop,说白了就是在你原来的代码执行前做一些操作,这样的好处就是不修改原来的代码逻辑,增强程序的功能,很方便。人生苦短,我用python,python中也有同样的功能,而且更方便,这个功能就是装饰器
1、无参数装饰器
无参的装饰器是最简单的,万事开头难,先挑个简单的下手,不要慌,慢慢来。
def aop(func): print("begin----------") func() print("end-----------") @aop def funcMethod(): print("run ") # 执行结果 #begin---------- #run #end----------- 复制代码
可以看到语法就是在需要装饰的函数上使用@aop ,aop 表示装饰器的函数,很简单对不对。。。
2、装饰有参数的函数
有参数的函数才是开发中的常态,所以怎么实现对有参数的构造函数进行装饰
def aop(func): def wrap(p1): print("开始") func(p1) print("结束") return wrap @aop def funcMethod(p1): print(p1) funcMethod("执行") 复制代码
可以看到这次比第一个例子稍微复杂一些,但是也能看出装饰器的底层原理,
想要修饰一个参数的函数,为此我们在装饰器函数内部定义了一个新的函数,同样的参数,并且将函数wrap 进行了返回,也就是替换了原来的函数funcMethod
知识点:装饰器函数替换了原来的函数,将原来的函数作为新函数的一部分。
3、通用的函数装饰器
通常来说我们想要实现通用装饰器,比如我们要实现一个函数的调用日志,这样每个函数的定义是不一样的,有的参数多,有的参数少,有的甚至没有参数。
def aop(func): def wrapper(*args, **kwargs): print('参数如下:') print(args) print(kwargs) result = func(*args, **kwargs) print("结束") return result return wrapper @aop def funcMethod(p1,p2): print(p1) print(p2) @aop def funcMethod2(): print("xxxxxx") funcMethod("执行","参数2") funcMethod2() 复制代码
注:args 形参前加' '表示可以接受多个实参值存进数组
kwargs对于在形参前加' '表示表示接受参数转化为字典类型
4、基于类的装饰器
class AopClazz(object): def __init__(self, f): self.f = f def __call__(self): print(" start") self.f() print(" end") @AopClazz def func(): print("func") func() 复制代码
Python 对某个对象是否能通过装饰器( @decorator)形式使用只有一个要求:decorator 必须是一个“可被调用
(callable)的对象。
对于这个 callable 对象,我们最熟悉的就是函数了。
除函数之外,类也可以是 callable 对象,只要实现了call 函数(上面几个盒子已经接触过了),还有比较少人使用的偏函数也是 callable 对象。
5、内置装饰器
特性装饰器:@property
类方法装饰器: @classmethod
静态方法装饰器:@staticmethod
import math class Circle: def __init__(self,radius): #圆的半径radius self.radius=radius @property def area(self): return math.pi * self.radius**2 #计算面积 @property def perimeter(self): return 2*math.pi*self.radius #计算周长 复制代码
通过@property装饰后的方法也可以像访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值;
其他的两个大家都很熟悉了,就不多介绍了
@staticmethod
返回的是一个staticmethod
类对象,而@classmethod
返回的是一个classmethod
类对象。他们都是调用的是各自的__init__()
构造函数。
总结:装饰器说白了就是使用函数替换当前的实现,没有太多秘密