On Mon, 21 Dec 2009 09:41:22 -0800, Denis Doria wrote: > Hi; > > I'm checking the best way to validate attributes inside a class.
There is no "best way", since it depends on personal taste. > Of > course I can use property to check it, but I really want to do it inside > the __init__: If you "really want to do it inside the __init__", then copy the code that you would put in the property's setter into the __init__ method. But why do you care that the check is inside the __init__ method? All that is really important is that the __init__ method *calls* the check, not where the check lives. > class A: > def __init__(self, foo, bar): > self.foo = foo #check if foo is correct > self.bar = bar Here are some ways of doing this, more or less in order of complexity and difficulty. (1) Don't validate at all. Just document that foo must be no more than five characters long, and if the caller pays no attention and passes a too-long string, any explosions that happen are their fault, not yours. class A: """Class A does blah blah. If foo is longer than five characters, behaviour is undefined. """ def __init__(self, foo = None, bar = None): self.foo = foo self.bar = bar (This may seem silly, but for more difficult constraints which are hard to test, it may be your only choice.) (2) Validate once only, at initialisation time: class A: def __init__(self, foo = None, bar = None): if len(foo) > 5: raise ValueError("foo is too big") self.foo = foo self.bar = bar Note that further assignments to instance.foo will *not* be validated. (3) Move the validation into a method. This is particularly useful if the validation is complex, or if you expect to want to over-ride it in a sub- class. class A: def __init__(self, foo = None, bar = None): self.validate(foo) self.foo = foo self.bar = bar def validate(self, foo): if len(foo) > 5: raise ValueError("foo is too big") Further assignments to instance.foo are still not validated. (4) Validate on every assignment to foo by using a property. Note that for this to work, you MUST use a new-style class. In Python 3, you don't need to do anything special, but in Python 2.x you must inherit from object: class A(object): def __init__(self, foo = None, bar = None): self.foo = foo # calls the property setter self.bar = bar def _setter(self, foo): if len(foo) > 5: raise ValueError("foo is too big") self._foo = foo def _getter(self): return self._foo foo = property(_getter, _setter, None, "optional doc string for foo") If you think this looks "too much like Java", well, sorry, but that's what getters and setters look like. But note that you never need to call the getter or setter explicitly, you just access instance.foo as normal. (5) Use explicit Java-style getter and setter methods. This avoids using property, so it doesn't need to be a new-style class: class A: def __init__(self, foo = None, bar = None): self.setfoo(foo) self.bar = bar def setfoo(self, foo): if len(foo) > 5: raise ValueError("foo is too big") self._foo = foo def getfoo(self): return self._foo If you want to write Java using Python syntax, this may be the solution for you. But be aware that Python programmers will laugh at you. (5) If the constraint on foo is significant enough, perhaps it should be made part of the type of foo. class FooType(str): # or inherit from list, or whatever... def __init__(self, x): if len(x) > 5: raise ValueError("initial value is too big, invalid FooType") class A: def __init__(self, foo = None, bar = None): self.foo = FooType(foo) self.bar = bar Other, more complex solutions include using decorators or even metaclass programming. Don't worry about these at this point, I'm just showing off *wink* Hope this helps, -- Steven -- http://mail.python.org/mailman/listinfo/python-list