Functions and classmethod
objects act as descriptors; both return a wrapper that when called will in turn call the underlying function with an extra parameter. The only difference between how functions and classmethod
objects behave is in what that extra parameter is.
To create a hybrid of the two approaches, build your own descriptor decorator:
from functools import wraps
class hybridmethod(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, cls):
context = obj if obj is not None else cls
@wraps(self.func)
def hybrid(*args, **kw):
return self.func(context, *args, **kw)
# optional, mimic methods some more
hybrid.__func__ = hybrid.im_func = self.func
hybrid.__self__ = hybrid.im_self = context
return hybrid
Here, we return a wrapper that'll use either the class or the instance as the first parameter, depending on what is available when the descriptor __get__
method is called.
Demo:
>>> class Foo(object):
... @hybridmethod
... def bar(cls_or_self):
... print 'Called with cls_or_self={!r}'.format(cls_or_self)
...
>>> Foo.bar()
Called with cls_or_self=<class '__main__.Foo'>
>>> Foo().bar()
Called with cls_or_self=<__main__.Foo object at 0x1043a4390>