aspect-oriented programming

Mark McEahern marklists at mceahern.com
Tue Jan 22 02:34:09 CET 2002


Pedro Rodriguez <pedro_rodriguez at club-internet.fr> wrote in
message news:<pan.2002.01.13.11.22.54.248401.9857 at club-internet.fr>...

> Pre/Post/Around methods : I posted a simple implementation for this,
> à la AspectJ (Java) and AspectR (Ruby). And comparing with AspectJ,
> I am sure Python can provide that kind of implementation in simple
> and elegant way, in comparison with the compiler and language
> modification AspectJ introduces.
>
> This is an example of a patch to the current problem in Python 2.2...

Pedro, I'm very delighted to find the sample code (reposted at the bottom of
this message) you posted previously showing an implemention of Aspect.  As
you noted, the sample implementation does not work with new-style classes:

  class A(object):
      def f(self, x):
          print "real f", x

  aspect.wrap_around("around_advice", A, "f")
  a = A()
  a.f(1)

Did you have a fix for that?

Cheers,

// mark

#! /usr/bin/env python
# --------------------------------------------------------------------------
----
# aspect.py
#
# From: Pedro Rodriguez (pedro_rodriguez at club-internet.fr)
# Subject: Re: From 'wrapping unbound' methods to 'aspect oriented' design
#   (Aspect implementation)
# Newsgroups: comp.lang.python
# Date: 2002-01-13 02:27:51 PST
# --------------------------------------------------------------------------
----

import new

class Aspect:
    def wrap_around(self, adviceName, cls, methodName):
        adviceMethod = getattr(self, adviceName)
        AdviceAround(adviceMethod, cls, methodName)

    def wrap_before(self, adviceName, cls, methodName):
        adviceMethod = getattr(self, adviceName)
        AdviceBefore(adviceMethod, cls, methodName)

    def wrap_after(self, adviceName, cls, methodName):
        adviceMethod = getattr(self, adviceName)
        AdviceAfter(adviceMethod, cls, methodName)

class Advice:
    def __init__(self, adviceMethod, cls, methodName):
        self.methodName = methodName
        self.adviceMethod = adviceMethod
        self.origMethod = getattr(cls, methodName)
        newMethod = new.instancemethod(self.do_aspect, None, cls)
        setattr(cls, methodName, newMethod)

    def do_advice(self, *args, **kwargs):
        inst = args[0]
        apply(self.adviceMethod \
            , (self.origMethod, self.methodName, inst) + args
            , kwargs
            )

    def do_method(self, *args, **kwargs):
        apply(self.origMethod, args, kwargs)

    def do_aspect(self, *args, **kwargs):
        raise NotImplementedError

class AdviceAround(Advice):
    def do_aspect(self, *args, **kwargs):
        apply(self.do_advice, args, kwargs)

class AdviceBefore(Advice):
    def do_aspect(self, *args, **kwargs):
        apply(self.do_advice, args, kwargs)
        apply(self.do_method, args, kwargs)

class AdviceAfter(Advice):
    def do_aspect(self, *args, **kwargs):
        apply(self.do_method, args, kwargs)
        apply(self.do_advice, args, kwargs)

# Sample code ---------------------------------------------------------

class A:
    def f(self, x, y):
        print "real f %s %s" % (x, y)

    def g(self, x):
        print "real g %s" % x

class B:
    def z(self, *args, **kwargs):
        print "real z %s %s" % (str(args), str(kwargs))


class MyAspect(Aspect):
    def around_advice(self, method, methodName, inst, *args, **kwargs):
        print "start"
        apply(method, args, kwargs)
        print "stop"

    def before_advice(self, method, methodName, inst, *args, **kwargs):
        print ">>>>>>>>>"
        print "before", methodName, inst, args, kwargs

    def after_advice(self, method, methodName, inst, *args, **kwargs):
        print "after", methodName, inst, args, kwargs
        print "<<<<<<<<<"

aspect = MyAspect()
aspect.wrap_around("around_advice", A, "f")
aspect.wrap_before("before_advice", A, "g")

aspect.wrap_before("before_advice", B, "z")
aspect.wrap_after("after_advice", B, "z")

a = A()
a.f(1,2)
a.g(3)

print

b = B()
b.z(1,2,3, x=42)
b.z(4)

#-----------------------------------------------------------------------
#This fails with Python 2.2 :
#    ...
#    newMethod = new.instancemethod(self.do_aspect, None, cls)
#TypeError: instancemethod() argument 3 must be class, not type
#-----------------------------------------------------------------------

class A(object):
    def f(self, x):
        print "real f", x

aspect.wrap_around("around_advice", A, "f")
a = A()
a.f(1)





More information about the Python-list mailing list