Elk provides a feature called “method modifiers”. You can also think of these as “hooks” or “advice”.
It’s probably easiest to understand this feature with a few examples:
class Example(elk.Elk):
def foo(self):
print " foo"
@elk.before('foo')
def _before_foo(self):
print "about to call foo"
@elk.after('foo')
def _after_foo(self):
print "just called foo"
@elk.around('foo')
def _around_foo(self, orig):
print " I'm around foo"
orig()
print " I'm still around foo"
Calling Example().foo() will produce the following output:
about to call foo
I'm around foo
foo
I'm still around foo
just called foo
As you can see, the before modifiers come before around modifiers, and after modifiers come last.
When there are multiple modifiers of the same type, the before and around modifiers run from the last added to the first, and after modifiers run from first added to last:
before 2
before 1
around 2
around 1
primary
around 1
around 2
after 1
after 2
Method modifiers can be used to add behavior to methods without modifying the definition of those methods.
One use the before modifier would be to do some sort of prechecking on a method call. For example:
def set_size(self, size):
self.size = size
@elk.before('set_size')
def _before_set_size(self, size):
if self.is_growing:
raise AttributeError('cannot set size while person is growing')
Similarly, an after modifier could be used for logging an action that was taken.
Note
The name of the method modifier must be unique. Beyond this the name is of little consequence, but it is recommended to begin with an underscore if it is not part of the class’ public API (it probably isn’t).
Note
The return values of both before and after modifiers are ignored.
Note
The method modifier must accept the same arguments as the original method.
An around modifier is more powerful than either a before or after modifier. It can modify the arguments being passed to the original method, and you can even decide to simply not call the original method at all. You can also modify the return value with an around modifier.
An around modifier receives the original method as the first positional argument after self. By convention, the original method is referred to as orig:
@elk.around('set_size')
def _around_set_size(self, orig, size):
if self.likes_small_things():
size /= 2
return orig(size)
Note
orig is a bound method, meaning that it is called directly without passing self as the first argument.