Skip to content

Instantly share code, notes, and snippets.

@aandr
Created May 5, 2011 13:41
Show Gist options
  • Save aandr/957043 to your computer and use it in GitHub Desktop.
Save aandr/957043 to your computer and use it in GitHub Desktop.
Python AOP using Class Decorators
import inspect
def aspectize(arg):
def decorate_method(func):
func.__before = []
func.__after = []
def decorated(*args, **kwargs):
for f in func.__before:
res = f(*args, **kwargs)
if res is not None:
return res
main_res = func(*args, **kwargs)
for f in func.__after:
res = f(main_res, *args, **kwargs)
if res is not None:
return res
return main_res
decorated.__before = func.__before
decorated.__after = func.__after
return decorated
if inspect.isclass(arg):
for attr in arg.__dict__:
if callable(arg.__dict__[attr]):
setattr(arg, attr, decorate_method(arg.__dict__[attr]))
return arg
elif callable(arg):
return decorate_method(arg)
else:
raise Exception("Don't know what to do with argument")
def before(method):
def decorator(advice):
method.__before.append(advice)
return decorator
def after(method):
def decorator(advice):
method.__after.append(advice)
return decorator
from aop import aspectize, before, after
"""
Example:
>>> x = MyClass()
>>> x.my_func()
6
my_func returned 6
6
>>> x.my_func()
7
my_func returned 7
7
>>> x.my_func()
8
my_func returned 8
8
"""
@aspectize
class MyClass:
def __init__(self):
self.x = 5
def my_func(self):
print(self.x)
return self.x
@before(MyClass.my_func)
def increase_x(self):
self.x += 1
@after(MyClass.my_func)
def log_my_func(res, self):
print("my_func returned " + str(res))
@pentos9
Copy link

pentos9 commented Sep 18, 2018

hi,there is something wrong with this code snippet.i got this error when i run this code:
Traceback (most recent call last):
File "/projects/achilles/app/base/aop_demo.py", line 22, in
@before(HandleClass.incr)
AttributeError: 'NoneType' object has no attribute 'incr'
(py 2.7)

that is how my code looks like:

def aspectize(arg):
    def decorate_method(func):
        func.__before = []
        func.__after = []

        def decorated(*args, **kwargs):
            for f in func.__before:
                res = f(*args, **kwargs)
                if res is not None:
                    return res

            main_res = func(*args, **kwargs)

            for f in func.__after:
                res = f(*args, **kwargs)
                if res is not None:
                    return res

            return main_res

        decorated.__before = func.__before
        decorated.__after = func.__after

        return decorated

    if inspect.isclass(arg):
        for attr in arg.__dict__:
            if callable(arg.__dict__[attr]):
                setattr(arg, attr, decorate_method(arg.__dict__[attr]))

    elif callable(arg):
        return decorate_method(arg)

    else:
        raise Exception("[Error]don't know what to do with this argument! ")


def before(method):
    def decorator(advice):
        method.__before.append(advice)

    return decorator


def after(method):
    def decorator(advice):
        method.__after.append(advice)

    return decorator

@aspectize
class HandleClass(object):
    def __init__(self):
        self.x = 5

    def incr(self):
        pprint(self.x)
        return self.x


@before(HandleClass.incr)
def increase_x(self):
    self.x += 1


@after(HandleClass.incr)
def log_func(res):
    pprint('[Return] {}'.format(str(res)))


def run():
    c = HandleClass()
    c.incr()
    pprint(c)


if __name__ == '__main__':
    run()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment