Splitting architecture apart via signals
Signals can be used to create code that's not coupled. It's a really nice solution to split code apart and makes things much more readable.
Let's take an example: user creation. When a user is created we might want to do following things:
Generally you solve this in following manner: import analytics
import other_service
import notifications
def create_user(...):
...
analytics.user_created(user)
other_service.user_created(user)
notifications.send_welcome_email(user)
The main problem with this approach is that you'll create a high coupling between your modules and eventually you'll meet the glory of circular imports. A better solution, using signals, is to simply fire off a user_created signal - firing off a signal will call all the listeners of the signal. E.g.: import signals
def create_user(...):
...
signals.send_signal('user_created', user=user)
This approach uncouples code, solves the problem with circular imports and improves readability. It's nize :-) The complex implementations of signalsIn Python the signals implementations are fairly complex (for me it seems like people have made the problem too hard), here are some signal implementations: Both these use weak references and their API is fairly complex (they can do lots of stuff - that's unneeded, at least in my applications). I have made my own little signals implementation, which solves my problems: SIGNALS = {}
def connect(signal_key, callback):
"""Connect `callback` to signal's callback sequence.
"""
if signal_key in SIGNALS:
SIGNALS[signal_key].append( callback )
else:
SIGNALS[signal_key] = [callback]
def send_signal(signal_key, *args, **kwargs):
"""Sending a signal will iterate over a signal's callback.
"""
if not signal_key in SIGNALS:
raise Exception('No handlers for signal: %s' % signal_key)
for callback in SIGNALS[signal_key]:
callback(*args, **kwargs)
Example: def reciver_1(x): print "hello"
def reciver_2(x): print "world"
signals_new.connect("hello", reciver_1)
signals_new.connect("hello", reciver_2)
signals_new.send_signal("hello", x=None)
I only add signals at the bootstrap, I don't need to remove signals and I don't need to have error handling. This makes the problem domain _very_ easy to solve as you can see.
Code
·
Code improvement
·
Code rewrite
·
Design
·
Python
·
Tips
•
25. Jan 2009
1 comment so far
Post a comment
Commenting on this post has expired.
|
Blog labels |