systempuntoout systempuntoout - 1 month ago 6
Python Question

Correct approach to validate attributes of an instance of class

Having a simple Python class like this:

class Spam(object):
__init__(self, description, value):
self.description = description
self.value = value


I would like to check the following constraints:


  • "description cannot be empty"

  • "value must be greater than zero"



Should I:

1. validate data before creating spam object ?

2. check data on
__init__
method ?

3. create an
is_valid
method on Spam class and call it with spam.isValid() ?

4. create an
is_valid
static method on Spam class and call it with Spam.isValid(description, value) ?

5. check data on setters declaration ?

6. etc.

Could you recommend a well designed/Pythonic/not verbose (on class with many attributes)/elegant approach?

Answer

You can use Python properties to cleanly apply rules to each field separately, and enforce them even when client code tries to change the field:

class Spam(object):
    def __init__(self, description, value):
        self.description = description
        self.value = value

    @property
    def description(self):
        return self._description

    @description.setter
    def description(self, d):
        if not d: raise Exception("description cannot be empty")
        self._description = d

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, v):
        if not (v > 0): raise Exception("value must be greater than zero")
        self._value = v

An exception will be thrown on any attempt to violate the rules, even in the __init__ function, in which case object construction will fail.

UPDATE: Sometime between 2010 and now, I learned about operator.attrgetter:

import operator

class Spam(object):
    def __init__(self, description, value):
        self.description = description
        self.value = value

    description = property(operator.attrgetter('_description'))

    @description.setter
    def description(self, d):
        if not d: raise Exception("description cannot be empty")
        self._description = d

    value = property(operator.attrgetter('_value'))

    @value.setter
    def value(self, v):
        if not (v > 0): raise Exception("value must be greater than zero")
        self._value = v