Aspect oriented Everything?

Andrew Dalke adalke at mindspring.com
Wed Aug 27 13:01:56 EDT 2003


Hung Jung Lu:
> The question is: are there code spots that are not factored? If you
> have ONE single class that has to implement the before, around, or
> after methods, sure, nothing wrong with what you have said. But, if
> you have
>
> class A:
>    def f1():
>        register()
>        ...
>        deregister()
> class B:
>    def f2():
>        register()
>        ...
>        deregister()
> class C:
>     def f3():
>        register()
>        ...
>        deregister()
>
> You start to ask your self: how come the register() deregister() parts
> are not factor out? How can I factor out these parts of code?

What about

>>> class RegisterFunc(object):
...    def __init__(self, f):
...       self.f = f
...    def __get__(self, obj, type = None):
...       return RegisterCall(self.f, obj)
...
>>> class RegisterCall(object):
...    def __init__(self, f, obj):
...       self.f = f
...       self.obj = obj
...    def __call__(self, *args, **kwargs):
...       register()
...       try:
...          self.f(self.obj, *args, **kwargs)
...       finally:
...          deregister()
...
>>> def register():
...    print "Register"
...
>>> def deregister():
...    print "Deregister"
...
>>> class Spam(object):
...    def spam(self):
...       print "I've been spammed!"
...      spam = RegisterFunc(spam)
...
>>> Spam.spam()
Register
I've been spammed!
Deregister
>>>


> If you don't have AOP, you would have to manually modify each class into:
  ...
> Notice that OOP or class
> inheritance will not allow you to factor out these types of
> "horizontal common code spots".

Hmm.  Given that, is what I'm doing above not OO programming?
You can derive from it, and because the methods are not changed
once the class is defined, I event get the proper behaviour that
the childrens' behaviour is more restrictive than the parent's.

(I point this out because pre-2.3 I would have used __getattr__
hooks to make a wrapper around the whole class, rather than
a per-method one like I did here.)

> To my, horizontal factorization is what AOP is all about. It goes
> beyond the before-, around-, after- hooks. I've written codes where I
> have many if statements in a base class method:
  ...
> but in OOP you will find
> out that common steps 1,2,4 will not be factored out, and that when
> you need to change the code in the common steps, you need to change in
> all subclasses, which is tedious and error-prone.

For this I would usually use a mixin or just call a function.  Or
change it so there are functions which can each modify a state,
as in

class Modifier:
  def between_1_and_2(self, state):
    ..
  def between_2_and_3(self, state):
    ..

class FixedRateModifier(Modifier):
  ...
class GovernmentBondModifier(Modifier):
  ...


def f(arg1, arg2, arg3, ...):
    modifiers = [FixedRateModifier(), GovernmentBondModifier()]
    state = State(arg1, arg2, arg3)
    do_step1_calculations(state)

    for m in modifiers:
      m.between_1_and_2(state)

    self.do_step2_calculations(state)

    for m in modifiers:
      m.between_2_and_3(state)

   ...

Is this a hand-written way of doing AOP?  (I wouldn't be surprised.
I didn't understand OO until I handwrote a system using typedefs
and lots of function pointers.)


> Clearly inheritance
> is not the way to implement properties/features like these ones. OOP
> just cannot solve the problem.

Agreed about the inheritance part.  Disagree that there are non-AOP
ways to address it.

                    Andrew
                    dalke at dalkescientific.com






More information about the Python-list mailing list