Function caller (to multiple receivers) interface This class is designed to call a similar function of multiple objects of multiple classes using a single interface (it is not for calling functions that return a value).

A potential usage will be sending same data to multiple writers (log writer, HTML generator and styled printer to console). 

Tested with Python 3.4.2

I've also included a test/example in the below code:

"""
caller module:
Contains Caller class - call multiple other classes or modules with
similar function definitions, (it is not for calling functions that 
returns a value)

Author : Bhathiya Perera
"""
class Caller():
    """call other classes or modules with
       similar function definitions"""
    def __init__(self, *receivers):
        """Initialize

        Parameters :                    
            receivers - va-arg receivers (can be objects, modules,
                        another caller , ....)    
        """
        self._names = []
        self._receivers = receivers

    def __getattr__(self, name):
        """Get attribute of a given name
        This will return 'self' therefore it can be called later
        """    
        self._names.append(name)
        return self

    def __call__(self, *args, **kw):
        """This class is callable with any arguments or key-value arguments
        It will then be posted to all receivers
        """
        if len(self._names) == 0:
            raise Exception("Cannot call")

        method_name = self._names.pop()
        for receiver in self._receivers:
            method = getattr(receiver, method_name)
            method(*args, **kw)

        return self

if __name__ == "__main__":
    # -------------------------------------------------
    # Test its usage
    class Receiver1():
        def a(self, arg):
            print ("Receiver1 - a", arg)

        def b(self, arg):
            print ("Receiver1 - b", arg)       

    class Receiver2():
        def a(self, arg):
            print ("Receiver2 - a", arg)

        def b(self, arg):
            print ("Receiver2 - b", arg)

    class Receiver3():
        def a(self, arg):
            print ("Receiver3 - a", arg)

        def b(self, arg):
            print ("Receiver3 - b", arg)

    c = Caller(Receiver3())
    d = Caller(Receiver1(), Receiver2(), c)  
    d.a("hello a")
    d.b("hello b")
    print ("-----")
    d.a.b.a.b.a.b.a("a")("b")("c")("d")("e")("f")("g")


If it was executed as a module it will print:




Receiver1 - a hello a
Receiver2 - a hello a
Receiver3 - a hello a
Receiver1 - b hello b
Receiver2 - b hello b
Receiver3 - b hello b
-----
Receiver1 - a a
Receiver2 - a a
Receiver3 - a a
Receiver1 - b b
Receiver2 - b b
Receiver3 - b b
Receiver1 - a c
Receiver2 - a c
Receiver3 - a c
Receiver1 - b d
Receiver2 - b d
Receiver3 - b d
Receiver1 - a e
Receiver2 - a e
Receiver3 - a e
Receiver1 - b f
Receiver2 - b f
Receiver3 - b f
Receiver1 - a g
Receiver2 - a g
Receiver3 - a g



Review for Python conventions and anything else.
If I understand correctly,
the purpose of Caller seems to be to call a function on multiple objects.
It works like this:


Construct a Caller x by passing 1 or more objects in the constructor
Call any method m on x, and it will be dispatched to method m of all objects


Right? The docstring doesn't explain this very well.
CallDispatcher might be a better name.

My impression is that you're discovering powerful features of Python,
and you're trying to use them because you can,
not because you have a concrete purpose.
Sort of like an exercise, not for real-life use.

It seems to me that __getattr__ is seriously abused.
I don't have experience overriding this method,
but I would guess it's designed to implement getters dynamically.
First of all,
adding getters dynamically seems like a hack that should be used with extreme care,
including a good justification that it's the best option.
Secondly,
instead of behaving as a getter,
this implementation mutates the object and returns self.
I see you did that to make chaining and currying possible,
it's interesting, but it seems a misuse of the language.

Another thing I don't like about the approach is the heavy dependence on duck typing.
The objects that can be used with Caller don't have to follow a well-defined interface,
they can be anything.
The user just has to make sure that when they call a .hello function on a Caller object,
all the objects inside have a .hello function defined.
It's great that Python let's us do this kind of thing,
but it doesn't mean that we should.
I prefer to have well-defined and well-documented interfaces,
with a list of legitimate methods that I'm allowed to call.

Python conventions

Instead of:


class Caller():



The class should be declared as:

class Caller:


Instead of:


    if len(self._names) == 0:



The Pythonic way:

    if not self._names:


Instead of:


        print ("Receiver3 - b", arg)



There should be no space before the opening paren:

        print("Receiver3 - b", arg)