I have a dispatcher that I use to send messages from one object to another. If Object A wants to send a message to Object B, he uses the Dispatcher to send the message for him. Object A doesn’t care how the Dispatcher sends the message – it might need to be queued and sent across threads for example.
When Object B receives the message, he might want to know who sent the message so that he can reply to him. In order to do this, when Object A tells the Dispatcher to send a message he also tells him who the messages is coming from.
Here is a simple example. Note: I create the A1, B1, and Dispatcher1 objects on-the-fly to simplify the example. Hopefully that is not too distracting.
import inspect
class Dispatcher1:
def send( self, srcObj, dstObj, *args, **kwargs ):
print 'D1.send', 'srcObj =', str(srcObj), 'dstObj = ', str(dstObj)
dstObj.recv( srcObj, args, kwargs )
class A1:
def run( self ):
print 'A1.run'
Dispatcher1().send( self, B1() )
def callback( self ):
print 'A1.callback'
class B1:
def recv( self, srcObj, *args, **kwargs ):
print 'B1.recv'
srcObj.callback()
if __name__ == '__main__':
A1().run()
print
Running the code gives this:
A1.run
D1.send srcObj = <__main__.A1 instance at 0x00B1AA58> dstObj = <__main__.B1 instance at 0x00A9E378>
B1.recv
A1.callback
This is pretty standard stuff, but in a powerful language like Python, it seems to be a waste to make Object A have to say ‘Hey, I’m the one sending this message.’ What I would like to do is have the Dispatcher figure that out himself and automatically specify Object A as the sender.
I can do this by inspecting the stack each time send is called. Here is a modified example.
import inspect
class Dispatcher2:
def send( self, dstObj, *args, **kwargs ):
srcObj = inspect.stack()[1][0].f_locals['self']
print 'Found srcObj =', str(srcObj)
print 'D2.send', 'srcObj =', str(srcObj), 'dstObj = ', str(dstObj)
dstObj.recv( srcObj, args, kwargs )
class A2:
def run( self ):
print 'A2.run'
Dispatcher2().send( B2() )
def callback( self ):
print 'A2.callback'
class B2:
def recv( self, srcObj, *args, **kwargs ):
print 'B2.recv'
srcObj.callback()
if __name__ == '__main__':
A2().run()
print
Running the code gives this:
A2.run
Found srcObj = <__main__.A2 instance at 0x00B1AA58>
D2.send srcObj = <__main__.A2 instance at 0x00B1AA58> dstObj = <__main__.B2 instance at 0x00A9E210>
B2.recv
A2.callback
This seems like a lot of work to get the caller from the stack not to mention the appropriate error-handling is missing.
Another alternative is to add a send() function to Object A and then use a decorator to add the ‘self’ parameter before calling the Dispatcher’s send() function. But I would rather not require a send() function in Object A. There are a lot of different objects that will be using the Dispatcher. I don’t want them to have to add functions to each of them.
Does anyone have any other suggestions on how to accomplish this?