Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python: hybrid between regular method and classmethod

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.

like image 673
Sławomir Lenart Avatar asked Aug 06 '13 11:08

Sławomir Lenart


People also ask

What is the difference between @staticmethod and Classmethod?

Class method can access and modify the class state. Static Method cannot access or modify the class state. The class method takes the class as parameter to know about the state of that class. Static methods do not know about class state.

When should you use a Classmethod Python?

You can use class methods for any methods that are not bound to a specific instance but the class. In practice, you often use class methods for methods that create an instance of the class. When a method creates an instance of the class and returns it, the method is called a factory method.

What is difference between class method and static method in Python?

Class methods don't need a class instance. They can't access the instance ( self ) but they have access to the class itself via cls . Static methods don't have access to cls or self . They work like regular functions but belong to the class's namespace.

What is the difference between a method and a function in Python?

Functions can be called only by its name, as it is defined independently. But methods can't be called by its name only, we need to invoke the class by a reference of that class in which it is defined, i.e. method is defined within a class and hence they are dependent on that class.


1 Answers

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>
like image 96
Martijn Pieters Avatar answered Oct 07 '22 20:10

Martijn Pieters