import functools

def _decorate_method(f, name):
    @functools.wraps(f)
    def __wrapper(self, *args, **kwds):
        print 'wrapped a method', f, name
        return f(self, *args, **kwds)
    return __wrapper


def _decorate_class(cls, name):
    original_init = cls.__init__

    def __init_wrapper(self, *args, **kwds):
        print 'wrapped a class __init__', cls, name
        return original_init(self, *args, **kwds)
    cls.__init__ = __init_wrapper
    return cls

def _make_decorator(name, f):
    if isinstance(f, type):
        print 'decorating class', f, name
        return _decorate_class(f, name)
    else:
        print 'decorating method', f, name
        return _decorate_method(f, name)

def my_decorator(arg='some-default'):
    """
    decorator generator logic engine wrapper

    determines if the thing to be wrapped is a method or a class, then
    calls the appropriate decorator generator
    """
    if isinstance(arg, str):
        # requires partial application, because the return must be a
        # function that takes a function as its argument
        return functools.partial(_make_decorator, arg)
    else:
        return _make_decorator('some-default', arg)



## examples
@my_decorator
@my_decorator()
@my_decorator('not-bar')
class Foo(object):
    @my_decorator
    def something_a(self):
        pass
    
    @my_decorator()
    def something_b(self):
        pass
    
    @my_decorator('not-foo')
    def something_c(self):
        pass

print 'instantiation here'
f = Foo()
print 'calling methods'
f.something_a()
f.something_b()
f.something_c()

## output
# decorating method <function something_a at 0x10f4a1320> some-default
# decorating method <function something_b at 0x10f4a1410> some-default
# decorating method <function something_c at 0x10f4a1500> not-foo
# decorating class <class '__main__.Foo'> not-bar
# decorating class <class '__main__.Foo'> some-default
# decorating class <class '__main__.Foo'> some-default
# instantiation here
# wrapped a class __init__ <class '__main__.Foo'> some-default
# wrapped a class __init__ <class '__main__.Foo'> some-default
# wrapped a class __init__ <class '__main__.Foo'> not-bar
# calling methods
# wrapped a method <function something_a at 0x10f4a1320> some-default
# wrapped a method <function something_b at 0x10f4a1410> some-default
# wrapped a method <function something_c at 0x10f4a1500> not-foo