Lightweight Python AOP
http://www.cs.tut.fi/~ask/aspects/aspects.html
足够简单,因此也很像个玩具或者随意的练习。
喜欢这个方案中把函数作为第一类对象的做法,wrap_around函数会动态complie一段代码来创建新函数来替代原有函数,并在新函数中调用方面(aspect)的代码和原函数。
缺点是当需要多个方面时它采用嵌套的方法来进行织入(weave),也就是说如果想在织入后从织入链中去掉一个方面会非常困难。而且把原函数改名保存的做法虽然直接看起来却不够优雅――如果类中恰好有和修改后的名称同名的函数怎么办?而且把改名后的函数(也包括其他一些需要的属性,比如方面调用时的堆栈)保存在函数所属类中,也就是说虽然在这个方案中把函数作为第一类对象来看待,但并不能把一般函数作为连接点(join point)。而对实例(instance)的织入会影响该类的所有实例。
Pythius.aop
http://cvs.sourceforge.net/viewcvs.py/pythius/pythius/pythius/aop.py?rev=1.36&content-type=text/vnd.viewcvs-markup
用metaclass实现的Aop,如果对应到Java上Aop的实现可以说是非常相似了――或者说很像是实现了Python版的动态代理。pythius.aop.Metaclass(这个名字起的可够糟糕……)作为元类(metaclass)其实例化的类会修改__getattr__、__setattr__的实现在其中拦截全部调用――包括函数、变量等等。它提供的例子是这样的:
>>> class Square:
__metaclass__ = pythius.aop.Metaclass # This is constant!
# This changes! Note that we are referring to an *instance*
# of an Aspect, not the Logger class itself.
_aspect = my_logger
…
这里织入的声明包含在类声明中,于是类和方面间是有很强的耦合,实际上这是完全没有必要的。完全可以把这个织入的声明抽象出来
>>> SquareWithLogger = pythius.aop.Metaclass(&aposSquareWithLogger&apos, (Square,), {&apos_aspect&apos:my_logger})
这会产生一个很像Decorator的子类,值得注意的是如果用动态代理来实现Aop那么动态代理其实不如叫作动态装饰器。这个实现方法支持方面extend来合并多个方面,不必非要进行嵌套织入,理论上也可以修改织入链――但没有提供对应的方法。
问题在于不支持对一般函数的织入。不支持实例的织入。Metaclass对类的改动太大,有些直觉上是不必要(比如已经通过修改__getattr__实现拦截为何还要从类中删去连接点的声明),可能导致一些依靠反射程序无法正常运行。另外类中具体的函数连接点实际上是被定义在方面中的,这个耦合很糟糕。
Aspects
http://www.logilab.org/projects/aspects/
定义了一个抽象方面AbstractAspect在其中保存原函数和方面――用户可以扩展这个方面,然后定义一个创建函数的函数在被创建的函数中依次调用方面和原函数。这个和Lightweight Python AOP的思路很像,但是因为用抽象方面把信息抽象一致地保存所以就不需要动态compile出新函数――相比之下Lightweight Python AOP通过一个递增的数字拼接处字符串来记录原函数和方面的做法就太过粗糙了。支持实例的织入。而且这个方法的思路本质上是可以支持一般函数的织入的,可惜在构造AbstractAspect时默认传入的参数是成员函数――但是可以很类似实现出支持一般函数的织入的抽象方面和调用函数。
另外,Weaver作为一个Singleton实现其不仅提供织入的功能同时还保存了被织入函数和方面的信息(比如防止一个方面被织入同一函数两次――不过我觉得这个假设毫无道理),这个Weaver很像是个容器。好处是虽然也采用了嵌套织入的方式但根据Weaver中的信息可以实现方面的拆卸――但我认为应该有依赖性更小的方式。
这个方案可以说十分注意不影响连接点,比如新函数替换连接点函数时保持__doc__仍然可用,值得借鉴。
PyContainer
http://pycontainer.sourceforge.net/
实现了Interceptor,还算不上Aop。另外实现的方式很奇特(如果不是奇怪),利用container的优势返回包装过的实例,这个实例重写了__getattr__方法当调用存在拦截器的函数时就会返回这个实例自身……因为这个实例同时实现了__call__方法其中依次调用拦截器和原函数。整个项目还是一个很粗糙的版本而且已经一年多没更新过了。
AOPTutorial–Doing AOP With TransWarp (Under Construction)
http://www.zope.org/Members/pje/Wikis/TransWarp/AOPTutorial
不知道这个该不该算成一个Aop的方案,因为看这篇文档感觉主要是在讲Mix-in。其中的Aspect像一个可以动态添加的基类。有趣的概念是如果Aspect包括一个类体系那么它每次混入的结果都会产生一个新的类体系。具体看文档吧,一两句话说不清楚。另外没看到代码不太清楚是怎么实现的,因为实在懒得下一个Zope了。
理想中的Python AOP
方面和类不应该存在任何耦合
支持函数、属性作为连接点
支持把各种函数都作为连接点,包括function, unbound method, instancemethod, class method, static method
支持before, after, around, throw
织入后除了连接点之外不会对程序的其他部分产生影响,比如dir()、__doc__应该还能正常工作
支持运行时刻连接点上方面的添加和卸载
不依赖容器