0

I have written a library which uses a user defined class that calculates some defined properties in a custom formula way. Later this user defined formulas are used in some library functions. The formulas have a permitted range for the common argument. The user therefore has to define the minimal and maximal permitted argument values. Before the usage it is important to check the permitted argument range.

The code below shows how it is currently done. The user has to write a subclass with the class arguments min and max as well as the set_all_attributes() method. In this method he can implement his custom code and he has to explicitly call the check_value_range() method. This subclassing needs some boilerplate code, the user has to write for each of the many custom subclasses. Especially the call of the check_value_range() method.

Now my question: Is there a better way to implement the boundary checking? Is it may be possible to call the check implicitly with help of a metaclass? For performance reasons, the check should only be done once for all class attributes.

from abc import ABCMeta, abstractmethod

class Base:
    __metaclass__ = ABCMeta

    def __init__(self, init_value=0):
        self.a = init_value
        self.b = init_value
        self.c = init_value

    def check_value_range(self, value):
        """make sure the value is in the permitted range"""
        if value < self.min or value > self.max:
            raise ValueError('value not in permitted range!')

    @abstractmethod
    def set_all_attributes(self, value):
        """force subclasses to override this method"""
        pass

class UserDefinedSubclass(Base):
    """user has to define the min and max class arguments 
    as well as the set_all_attributes() method"""
    min = 0
    max = 10

    def set_all_attributes(self, value):
        """the user has to explicitly call the
        check_value_range() method"""
        self.check_value_range(value)
        self.a = 1+2*value
        self.b = 2+5*value
        self.c = 3+4*value

def some_library_function(user_class):
    u = user_class()
    u.set_all_attributes(2)
    return u.a + u.b + u.c

# usage
print some_library_function(UserDefinedSubclass)
geothachankary
  • 1,040
  • 1
  • 17
  • 30
  • possible duplicate of [Best way to check function arguments in Python](http://stackoverflow.com/questions/19684434/best-way-to-check-function-arguments-in-python) – thodic Jun 04 '15 at 11:06
  • Why not use descriptors for the attributes that need to be within certain ranges? – jonrsharpe Jun 04 '15 at 11:07
  • 1
    You can also take a look at Enthought Traits module. It allows you to define the type and boundaries of your variables, and raise an Exception if it doesn't fit. It's basically the same as you did here, but the synthax is really simple and the value checking is implemented in C, so you don't have performance issues. – CoMartel Jun 04 '15 at 11:20
  • 1
    If you're open to third-party libraries, see also [`contracts`](http://andreacensi.github.io/contracts/) (you would decorate `set_all_attributes` with `@contract(value='>=0,<=10')`). – jonrsharpe Jun 04 '15 at 12:26

0 Answers0