Writing a wrapper function WITHOUT using decorators
When I first started learning about Python decorators I found them pretty confusing an unintuitive, and it took me a while before I started using them. What I often want to do is modify a function with some extra functionality without having to add the extra code in my original function. Decorators are excellent for doing that, but if you find them confusing (which I did) then you can write a wrapper like this:
def wrap(agent): assert hasattr(agent, 'loop') lfunc = agent.loop def before_loop(): print('Before loop') def after_loop(): print('Doing stuff after loop') def wrapped(*args, **kwargs): before_loop() try: lfunc(*args, **kwargs) except Exception, e: print(e) after_loop() agent.loop = wrapped class TestAgent: def loop(self, n): for i in range(n): print('In loop') print(x) if __name__ == '__main__': a = TestAgent() wrap(a) a.loop(5)
if you run the script you will see that the before_loop and after_loop are also executed:
Before loop In loop In loop In loop In loop In loop Doing stuff after loop
The try/except block in wrapper() makes sure that after_loop() is called even if loop() throws an exception.
You should not forget to use a copy of the loop function (third line in the example above) as it will cause a RuntimeError due to infinite recursion. So this will crash:
def wrap_broken(agent): assert hasattr(agent, 'loop') def before_loop(): print('Before loop') def after_loop(): print('Doing stuff after loop') def wrapped(*args, **kwargs): before_loop() agent.loop(*args, **kwargs) after_loop() agent.loop = wrapped class TestAgent: def loop(self, n): for i in range(n): print('In loop') if __name__ == '__main__': a = TestAgent() wrap_broken(a) a.loop(5)