Search code examples
pythonpython-3.xvalidationpython-decorators

TypeError with Validation decorator in class method


I am trying to use a simple validation decorator inside a class:

import numpy as np

def validate_decorator(func):
    def func_wrapper(value):
        if value < 0:
            raise Exception("Not valid!")
        return func(value)
    return func_wrapper


class MyClass:
    def __init__(self):
        self.my_array = np.zeros(shape=(10,))
        self.idx = 0

    @validate_decorator
    def insert_value(self, value):
        self.my_array[self.idx] = value
        self.idx += 1

    def __str__(self):
        return f"{self.my_array[:self.idx]}"


a = MyClass()
a.insert_value(3.14)

This gives

TypeError: func_wrapper() takes 1 positional argument but 2 were given

I do not understand this error.

If I modify the func_wrapper to also take a self argument and return self (instead of func(value)) then there is no TypeError but, as expected, the insert_value is not executed.

Can someone help me understand how to use this simple decorator inside my class?


Solution

  • I've added self argument to func_wrapper and changed func_wrapper's return value to func(self, value). It works now, insert_value is executed.

    Class instance method always has this required self attribute unless converted to class method or static method: What is the purpose of the word 'self', in Python?

    import numpy as np
    
    def validate_decorator(func):
        def func_wrapper(self, value):
            if value < 0:
                raise Exception("Not valid!")
            return func(self, value)
        return func_wrapper
    
    
    class MyClass:
        def __init__(self):
            self.my_array = np.zeros(shape=(10,))
            self.idx = 0
    
        @validate_decorator
        def insert_value(self, value):
            self.my_array[self.idx] = value
            self.idx += 1
            print('EXECUTED!')
    
        def __str__(self):
            return f"{self.my_array[:self.idx]}"
    
    
    a = MyClass()
    a.insert_value(3.14)