patternpythonMinor
Hooking with Python3 Decorators
Viewed 0 times
withdecoratorshookingpython3
Problem
I wrote this prototype after reading the Wikipedia article on hooking. I didn't bother to read any of the code examples listed there because, well, I just didn't. I don't have a good excuse.
The documentation in this file should tell you enough about its purpose and intended usage. I'm looking for a confirmation of whether I even understand what hooks are and how they should be used. I'm also curious about any sort of preferred method of implementation or any way that I could improve these two objects (
```
"""Implement hooks with a simple interface using decorators.
The Hook class creates a function that can be placed in code as an
anchoring point for as yet undetermined functionality, while the
OnHook function creates the interface to that functionality.
To create a hook, use the @Hook decorator on an empty function of
your chosen name. The function's __call__ method will be generated
by the decorator. Then, create a function that accepts a function
as an argument and adds it to the targets callback by using @OnHook.
OnHook expects the target hook as an argument.
Example:
@Hook # decorator, no args
def my_hook(): pass # empty func, no params
@OnHook(my_hook) # decorator, hook as arg
def on_my_hook(func): pass # empty func, func as param
To add a callback to the new hook, use:
on_my_hook(my_callback)
When the hook is executed, your callback will be executed along with
any other callbacks that have been registered.
Written 2014-02-02 by Jack Stout.
"""
class Hook:
"""Decorator to create a hook."""
def __init__(self, func):
self.callbacks = []
def __call__(self):
for callback in self.callbacks:
callback()
def OnHook(target):
"""Decorator to create an interface to a hook.
Requires a target hook as only argument.
"""
def decorator(func):
def add_callback(func):
target.callbac
The documentation in this file should tell you enough about its purpose and intended usage. I'm looking for a confirmation of whether I even understand what hooks are and how they should be used. I'm also curious about any sort of preferred method of implementation or any way that I could improve these two objects (
Hook and OnHook).```
"""Implement hooks with a simple interface using decorators.
The Hook class creates a function that can be placed in code as an
anchoring point for as yet undetermined functionality, while the
OnHook function creates the interface to that functionality.
To create a hook, use the @Hook decorator on an empty function of
your chosen name. The function's __call__ method will be generated
by the decorator. Then, create a function that accepts a function
as an argument and adds it to the targets callback by using @OnHook.
OnHook expects the target hook as an argument.
Example:
@Hook # decorator, no args
def my_hook(): pass # empty func, no params
@OnHook(my_hook) # decorator, hook as arg
def on_my_hook(func): pass # empty func, func as param
To add a callback to the new hook, use:
on_my_hook(my_callback)
When the hook is executed, your callback will be executed along with
any other callbacks that have been registered.
Written 2014-02-02 by Jack Stout.
"""
class Hook:
"""Decorator to create a hook."""
def __init__(self, func):
self.callbacks = []
def __call__(self):
for callback in self.callbacks:
callback()
def OnHook(target):
"""Decorator to create an interface to a hook.
Requires a target hook as only argument.
"""
def decorator(func):
def add_callback(func):
target.callbac
Solution
This appears to be an implementation of something akin to the observer pattern. Your implementation is straightforward enough, but there are two things that jump out at me.
First, I'm surprised that this involves two top-level decorators? I think I would rather see a pattern similar to what
Second, I'm a little confused about your larger use case. Do hooks have a chance to change the inputs or outputs of the hooked function? Are you working on this project with other people who may be more used to some particular approach? (If so, it's easier for them to work with if it matches the approach they expect.) Are these phases easier to implement as functions called on an instance or a subclass?
First, I'm surprised that this involves two top-level decorators? I think I would rather see a pattern similar to what
property provides. Namely, rather than exposing both @Hook and @OnHook, make @Hook add an attribute to the function that can itself, as a decorator, hook other functions to the first (implementation left as an exercise):@Hook
def pre_initiative(): pass
@pre_initiative.when_called # or preferred name
def dummy_func_1(): print("pre-initiative!")Second, I'm a little confused about your larger use case. Do hooks have a chance to change the inputs or outputs of the hooked function? Are you working on this project with other people who may be more used to some particular approach? (If so, it's easier for them to work with if it matches the approach they expect.) Are these phases easier to implement as functions called on an instance or a subclass?
class Player:
def pre_initiative(self): pass
def post_initiative(self): pass
def encounter(players):
for player in players:
player.pre_initiative()
for player in players:
player.post_initiative()Code Snippets
@Hook
def pre_initiative(): pass
@pre_initiative.when_called # or preferred name
def dummy_func_1(): print("pre-initiative!")class Player:
def pre_initiative(self): pass
def post_initiative(self): pass
def encounter(players):
for player in players:
player.pre_initiative()
for player in players:
player.post_initiative()Context
StackExchange Code Review Q#41115, answer score: 2
Revisions (0)
No revisions yet.