Question

I have two classes: Account and Operator. Account contains a list of Operators. Now, whenever an operator (in the list) receives a message I want to notify Account object to perform some business logic as well.

I think of three alternatives on how to achieve this:

1) Hold a reference within Operator to the container [Account] object and call methods directly. Not absolutely good because of circular references.

2) Use events. As far as I know there is no built-in event handling mechanism in Python. So, this one is a bit tricky to implement.

3) Don't send messages to Operators directly. Instead, operate only Accounts, and within them, internally, handler operators. This one is a bit limiting because in this case I cannot pass around references to operators.

I wonder which approach is the most advantageous from the architectural point of view. How do you usually handle this task?

It would be great if you could point out snippets in Python.

Was it helpful?

Solution

You're over-thinking this. Seriously. Python isn't C++; your concerns are non-issues in Python. Just write what makes sense in your problem domain.

" Not absolutely good because of circular references."

Why not? Circularity is of no relevance here at all. Bidirectional relationships are great things. Use them. Python garbage collects them just fine without any thinking on your part.

What possible problem do you have with mutual (birectional) relationships?

"...operate only Accounts, and within them, internally, handler operators. This one is a bit limiting because in this case I cannot pass around references to operators. "

What? Your Operators are Python objects, pass all you want. All Python objects are (in effect) references, don't sweat it.

What possible problem do you have with manipulating Operator objects?

OTHER TIPS

There is no "one-size-fits-all" solution for the Observer pattern. But usually, it's better to define an EventManager object where interested parties can register themselves for certain events and post these events whenever they happen. It simply creates less dependencies.

Note that you need to use a global EventManager instance, which can be problematic during testing or from a general OO point of view (it's a global variable). I strongly advise against passing the EventManager around all the time because that will clutter your code.

In my own code, the "key" for registering events is the class of the event. The EventManager uses a dictionary (event class -> list of observers) to know which event goes where. In the notification code, you can then use dict.get(event.__class__, ()) to find your listeners.

I would use event handling for this. You don't have to implement it yourself -- I use pydispatcher for exactly this kind of event handling, and it's always worked very well (it uses weak references internally, to avoid the circular reference problem).

Also, if you're using a gui framework, you might already have an event framework you can hook into, for example PyQt has signals and slots.

>>> class Account(object):
...     def notify(self):
...         print "Account notified"
...
>>> class Operator(object):
...     def __init__(self, notifier):
...         self.notifier = notifier
...
>>> A = Account()
>>> O = Operator(A.notify)
>>> O.notifier()
Account notified
>>> import gc
>>> gc.garbage
[]
>>> del A
>>> del O
>>> gc.garbage
[]

One thing you may not know about instance methods is that they're bound when looked up when using the dot syntax. In other words saying A.notify automatically binds the self parameter of notify to A. You can then hold a reference to this function without creating uncollectable garbage.

Lastly, you can always use Kamaelia for this type of thing.

There are Observer pattern snippets all over the Web. A good source of reliable code is active state, E.G :

http://code.activestate.com/recipes/131499/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top