利用metaclass实现python的aop

修行Python个把星期,终于有点成果了,呵呵,一个利用metaclass实现的aop。

其实python这类非常动态的语言要实现AOP是很容易的,所以首先我们要来先定义一个metaclass

然后我们要在__new__()这个metaclass 的时候动态植入方法到要调用地方法的前后。

具体代码如下:

<bgsound cep="0"><span style="color: #008080;"> 1</span><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""><span style="color: #000000;"><br></span><span style="color: #008080;"> 2</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #800080;">__author__</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">alex</span><span style="color: #800000;">"</span><span style="color: #000000;"><br></span><span style="color: #008080;"> 3</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #800080;">__date__</span> <span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">$2008-12-5 23:54:11$</span><span style="color: #800000;">"</span><span style="color: #000000;"><br></span><span style="color: #008080;"> 4</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #800080;">__name__</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">pyaop</span><span style="color: #800000;">"</span><span style="color: #000000;"><br></span><span style="color: #008080;"> 5</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""><br></span><span style="color: #008080;"> 6</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #800000;">'''</span><span style="color: #800000;"><br></span><span style="color: #008080;"> 7</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">这个metaclass是实现AOP的基础<br></span><span style="color: #008080;"> 8</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #800000;">'''</span><span style="color: #000000;"><br></span><span style="color: #008080;"> 9</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #0000ff;">class</span><span style="color: #000000;"> pyaop(type):<br></span><span style="color: #008080;">10</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #800000;">'''</span><span style="color: #800000;"><br></span><span style="color: #008080;">11</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    这个空方法是用来将后面的beforeop和afterop初始化成函数引用<br></span><span style="color: #008080;">12</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #800000;">'''</span><span style="color: #000000;"><br></span><span style="color: #008080;">13</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> nop(self):<br></span><span style="color: #008080;">14</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        </span><span style="color: #0000ff;">pass</span><span style="color: #000000;"><br></span><span style="color: #008080;">15</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #800000;">'''</span><span style="color: #800000;"><br></span><span style="color: #008080;">16</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    下面这两个变量是类变量,也就是存放我们要植入的两个函数的地址的变量<br></span><span style="color: #008080;">17</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #800000;">'''</span><span style="color: #000000;"><br></span><span style="color: #008080;">18</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    beforeop</span><span style="color: #000000;">=</span><span style="color: #000000;">nop<br></span><span style="color: #008080;">19</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    afterop</span><span style="color: #000000;">=</span><span style="color: #000000;">nop<br></span><span style="color: #008080;">20</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #800000;">'''</span><span style="color: #800000;"><br></span><span style="color: #008080;">21</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    设置前后两个植入函数的类函数<br></span><span style="color: #008080;">22</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #800000;">'''</span><span style="color: #000000;"><br></span><span style="color: #008080;">23</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    @classmethod<br></span><span style="color: #008080;">24</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> setbefore(self,func):<br></span><span style="color: #008080;">25</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        pyaop.beforeop</span><span style="color: #000000;">=</span><span style="color: #000000;">func<br></span><span style="color: #008080;">26</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    @classmethod<br></span><span style="color: #008080;">27</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> setafter(self,func):<br></span><span style="color: #008080;">28</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        pyaop.afterop</span><span style="color: #000000;">=</span><span style="color: #000000;">func<br></span><span style="color: #008080;">29</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #800000;">'''</span><span style="color: #800000;"><br></span><span style="color: #008080;">30</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    初始化metaclass的函数,这个函数最重要的就是第四个参数,dict通过这个参数我们可以修改类的属性(方法)<br></span><span style="color: #008080;">31</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #800000;">'''</span><span style="color: #000000;"><br></span><span style="color: #008080;">32</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__new__</span><span style="color: #000000;">(mcl,name,bases,dict):<br></span><span style="color: #008080;">33</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        </span><span style="color: #0000ff;">from</span><span style="color: #000000;"> types </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> FunctionType </span><span style="color: #008000;">#</span><span style="color: #008000;">加载类型模块的FunctionType</span><span style="color: #008000;"><br></span><span style="color: #008080;">34</span><span style="color: #008000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #000000;">        obj</span><span style="color: #000000;">=</span><span style="color: #000000;">object() </span><span style="color: #008000;">#</span><span style="color: #008000;">定义一个空对象的变量</span><span style="color: #008000;"><br></span><span style="color: #008080;">35</span><span style="color: #008000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #000000;">        </span><span style="color: #800000;">'''</span><span style="color: #800000;"><br></span><span style="color: #008080;">36</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        这个就是要植入的方法,func参数就是我们要调用的函数<br></span><span style="color: #008080;">37</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        </span><span style="color: #800000;">'''</span><span style="color: #000000;"><br></span><span style="color: #008080;">38</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> aop(func):<br></span><span style="color: #008080;">39</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">            </span><span style="color: #800000;">'''</span><span style="color: #800000;"><br></span><span style="color: #008080;">40</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">            我们用这个函数来代替将要调用的函数<br></span><span style="color: #008080;">41</span><span style="color: #800000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">            </span><span style="color: #800000;">'''</span><span style="color: #000000;"><br></span><span style="color: #008080;">42</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">            </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> wrapper(</span><span style="color: #000000;">*</span><span style="color: #000000;">args, </span><span style="color: #000000;">**</span><span style="color: #000000;">kwds):<br></span><span style="color: #008080;">43</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">                pyaop.beforeop(obj) </span><span style="color: #008000;">#</span><span style="color: #008000;">调用前置函数</span><span style="color: #008000;"><br></span><span style="color: #008080;">44</span><span style="color: #008000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #000000;">                value </span><span style="color: #000000;">=</span><span style="color: #000000;"> func(</span><span style="color: #000000;">*</span><span style="color: #000000;">args, </span><span style="color: #000000;">**</span><span style="color: #000000;">kwds) </span><span style="color: #008000;">#</span><span style="color: #008000;">调用本来要调用的函数</span><span style="color: #008000;"><br></span><span style="color: #008080;">45</span><span style="color: #008000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #000000;">                pyaop.afterop(obj) </span><span style="color: #008000;">#</span><span style="color: #008000;">调用后置函数</span><span style="color: #008000;"><br></span><span style="color: #008080;">46</span><span style="color: #008000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #000000;">                </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> value </span><span style="color: #008000;">#</span><span style="color: #008000;">返回</span><span style="color: #008000;"><br></span><span style="color: #008080;">47</span><span style="color: #008000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #000000;">            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> wrapper<br></span><span style="color: #008080;">48</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        </span><span style="color: #008000;">#</span><span style="color: #008000;">在类的成员列表中查找即将调用的函数</span><span style="color: #008000;"><br></span><span style="color: #008080;">49</span><span style="color: #008000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #000000;">        </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> attr, value </span><span style="color: #0000ff;">in</span><span style="color: #000000;"> dict.iteritems():<br></span><span style="color: #008080;">50</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">            </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> isinstance(value, FunctionType):<br></span><span style="color: #008080;">51</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">                dict[attr] </span><span style="color: #000000;">=</span><span style="color: #000000;"> aop(value) </span><span style="color: #008000;">#</span><span style="color: #008000;">找到后用aop这个函数替换之</span><span style="color: #008000;"><br></span><span style="color: #008080;">52</span><span style="color: #008000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #000000;">        obj</span><span style="color: #000000;">=</span><span style="color: #000000;">super(pyaop, mcl).</span><span style="color: #800080;">__new__</span><span style="color: #000000;">(mcl, name, bases, dict) </span><span style="color: #008000;">#</span><span style="color: #008000;">调用父类的__new__()创建self</span><span style="color: #008000;"><br></span><span style="color: #008080;">53</span><span style="color: #008000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #000000;">        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> obj<br></span><span style="color: #008080;">54</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span></bgsound>

 

使用的时候,如果我们要拦截一个类A的方法调用,就这样子:

 

<bgsound cep="1"><span style="color: #008080;"> 1</span><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""><span style="color: #0000ff;">class</span><span style="color: #000000;"> A(object):<br></span><span style="color: #008080;"> 2</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #800080;">__metaclass__</span> <span style="color: #000000;">=</span><span style="color: #000000;"> pyaop<br></span><span style="color: #008080;"> 3</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> foo(self):<br></span><span style="color: #008080;"> 4</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        total </span><span style="color: #000000;">=</span><span style="color: #000000;"> 0<br></span><span style="color: #008080;"> 5</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> i </span><span style="color: #0000ff;">in</span><span style="color: #000000;"> range(</span><span style="color: #000000;">100000</span><span style="color: #000000;">):<br></span><span style="color: #008080;"> 6</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">            total </span><span style="color: #000000;">=</span><span style="color: #000000;"> total</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;"><br></span><span style="color: #008080;"> 7</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        </span><span style="color: #0000ff;">print</span><span style="color: #000000;"> total<br></span><span style="color: #008080;"> 8</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""><br></span><span style="color: #008080;"> 9</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> foo2(self):<br></span><span style="color: #008080;">10</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        </span><span style="color: #0000ff;">from</span><span style="color: #000000;"> time </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> sleep<br></span><span style="color: #008080;">11</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        total </span><span style="color: #000000;">=</span><span style="color: #000000;"> 0<br></span><span style="color: #008080;">12</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> i </span><span style="color: #0000ff;">in</span><span style="color: #000000;"> range(</span><span style="color: #000000;">100000</span><span style="color: #000000;">):<br></span><span style="color: #008080;">13</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">            total </span><span style="color: #000000;">=</span><span style="color: #000000;"> total</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;"><br></span><span style="color: #008080;">14</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">            sleep(</span><span style="color: #000000;">0.0001</span><span style="color: #000000;">)<br></span><span style="color: #008080;">15</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">        </span><span style="color: #0000ff;">print</span><span style="color: #000000;"> total</span></bgsound>

 

最后我们只需要:

 

<bgsound cep="2"><span style="color: #008080;"> 1</span><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""><span style="color: #0000ff;">def</span><span style="color: #000000;"> beforep(self):<br></span><span style="color: #008080;"> 2</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(</span><span style="color: #800000;">'</span><span style="color: #800000;">before</span><span style="color: #800000;">'</span><span style="color: #000000;">)<br></span><span style="color: #008080;"> 3</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #0000ff;">def</span><span style="color: #000000;"> afterp(self):<br></span><span style="color: #008080;"> 4</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(</span><span style="color: #800000;">'</span><span style="color: #800000;">after</span><span style="color: #800000;">'</span><span style="color: #000000;">)<br></span><span style="color: #008080;"> 5</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""><br></span><span style="color: #008080;"> 6</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt=""></span><span style="color: #0000ff;">if</span> <span style="color: #800080;">__name__</span> <span style="color: #000000;">==</span> <span style="color: #800000;">"</span><span style="color: #800000;">__main__</span><span style="color: #800000;">"</span><span style="color: #000000;">:<br></span><span style="color: #008080;"> 7</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    pyaop.setbefore(beforep)<br></span><span style="color: #008080;"> 8</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    pyaop.setafter(afterp)<br></span><span style="color: #008080;"> 9</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    a</span><span style="color: #000000;">=</span><span style="color: #000000;">A()<br></span><span style="color: #008080;">10</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    a.foo()<br></span><span style="color: #008080;">11</span><span style="color: #000000;"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt="">    a.foo2()</span></bgsound>

 这样子在执行代码的时候就得到了如下结果

before
100000
after
before
100000
after

这段代码耗时一天才调通(汗颜),是基于园里另外一贴 http://www.cnblogs.com/cavingdeep/archive/2006/08/22/483056.html 

并感谢python讨论群69828975里的大虾Seewind(310380)给予的无私帮助

欢迎各位python大牛给予斧正

你可能感兴趣的:(AOP,python)