Question

sometimes I have need to write class with static methods, however with possibility to initialized it and keep state (object)

sth like:

class A:
  @classmethod
  def method(cls_or_self):
    # get reference to object when A().method() or to class when A.method()
    code

what I have now is:

class A:
   def method(self = None, *params): code
   # or
   def method2(self = None, **params): code
   # but what I need is rather normal parameters, not optional and named args:
   def method3(self_or_cls, a, b=1, c=2, *p, **kw): code

please do not write about differences between staticmethod and classmethod. I am interested if such decorator exists (in more or less standard libs) and moreover if above is suitable for PEP.

Was it helpful?

Solution

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>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top