from zope.interface import implementer, Interface, implements
from zope.component import getSiteManager, getMultiAdapter
from zope.component import adapter

class IGenericFunction(Interface):
    """
    Marker interface. Any interface would do though.
    """

class IFoo(Interface):
    pass

class IBar(Interface):
    pass

class Foo(object):
    implements(IFoo)

class Bar(object):
    implements(IBar)

def generic(*type_sig):
    def register(gen_func):
        name = gen_func.__name__

        def new_func(*args):
            obj = getMultiAdapter(args, IGenericFunction, name=name)
            return obj

        implementer(IGenericFunction)(gen_func)
        adapter(type_sig)(gen_func)

        sm = getSiteManager()
        sm.registerAdapter(gen_func, type_sig, name=name)
        new_func.__name__ = name

        return new_func

    return register

if __name__ == '__main__':
    @generic(int, int)
    def funcy(a, b):
        return "Ints: %d, %d" % (a, b)

    @generic(str, str)
    def funcy(a, b):
        return "Strings: %s, %s" % (a, b)

    foo = Foo()
    bar = Bar()

    @generic(IFoo)
    def funcy(a):
        return "I got an IFoo"

    @generic(IBar)
    def funcy(a):
        return "I got an IBar"

    @generic(IFoo, int)
    def funcy(f, a):
        return "I got an IFoo and int: %d" % a

    print funcy(1,2)
    print funcy("a", "b")
    print funcy(foo)
    print funcy(bar)
    print funcy(foo, 10)
    print funcy.__name__
