Search code examples
pythonpython-decorators

pythonic way of decorating classmethods


Given the following example:

class A:
    def f(self, x):
        return 2*x 

I would like to write another method which uses f above but adds a constant, i.e.

class A:
        def f(self, x):
            return 2*x
        def g(self, x):
            return self.f(x) + 10

This would be one way. However, this smells very much like decorating! What would be the proper pythonic way to do this?


Solution

  • You can write a simple function outside the class:

    def add_val(f):
      def wrapper(cls, _x):
        return f(cls, _x) + 10
      return wrapper
    
    
    class A:
      @add_val
      def f(self, x):
        return 2*x 
    print(A().f(20))
    

    Output:

    50
    

    Edit: you can utilize functools.wraps with a classmethod in Python3. The wrapped function f will return x*2 and the decorator g will add 10 to the returned result of the function passed to it. However, to be able to save the original functionality of f, you can utilize the __wrapped__ attribute:

    import functools
    def g(f):
      @functools.wraps(f)
      def wrapper(cls, _x):
        return f(cls, _x)+10
      return wrapper
    
    class A:
       @classmethod
       @g
       def f(cls, x):
         return x*2
    
    f_1 = functools.partial(A.f.__wrapped__, A)
    print(A.f(4))
    print(f_1(4))
    

    Output:

    18
    8