from functools import wraps




def valuedispatch(original):
    original._registry = {}

    @wraps(original)
    def new(*args, **kwargs):
        try:
            first = args[0]
        except IndexError:
            func = original
        else:
            func = original._registry.get(first, original)
        return func(*args, **kwargs)

    def register(value):
        print('register', locals())

        def wrap_specific(value):
            print('wrap_specific', locals())

            def _wrapper(specific):
                print('_wrapper', locals())
                original._registry[value] = specific
                return specific

            return _wrapper

        return wrap_specific(value)

    new.register = register
    return new


print('valuedispatch')
@valuedispatch
def fun(arg):
    "Prints arg."
    print(arg)

print('register fun')
@fun.register('greet')
def _(arg):
    print('Hello, world!')

print('register leave')
@fun.register('leave')
def _(arg):
    print('Goodbye!')


fun('Alice') # Alice
fun('greet') # Hello, World!
fun('leave') # Goodbye!


print(fun.__doc__) # Prints arg