10

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.

2
  • 2
    You mean a hybrid between a classmethod and a regular method. Commented Aug 6, 2013 at 11:18
  • See also Same name for classmethod and instancemethod which has more, and currently better maintained, answers. Commented Jan 3 at 11:28

1 Answer 1

22

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>
Sign up to request clarification or add additional context in comments.

2 Comments

... such fast and amazing that I must wait to accept answer (stackoverflow reqs), but what about classmethod ? - for me above decorator looks much functional, even to suggest overwrite the clasmethod or add third standard decorator for methods. I know it require strong criticism.
The classmethod decorator serves a different goal; methods that are ambiguous about their behaviour (act one way or another based on context) are not too pythonic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.