Decorator for validation - inefficient?
bryanvick at gmail.com
Sun Nov 2 18:33:41 CET 2008
On Nov 1, 6:57 pm, Steven D'Aprano <st... at REMOVE-THIS-
> On Sat, 01 Nov 2008 17:12:33 -0700, Bryan wrote:
> > The list of validation error descriptions is returned instead of raising
> > exceptions so clients can show the errors to the user for fixing.
> > Raising exceptions seems like an uneeded burden for the client, as there
> > is nothing exceptional about bad user input.
> But of course there is. Exceptional doesn't mean rare. In this case, it
> just means it's not the "normal" input which is expected.
> > Instead, I want to raise an
> > exception if a client actually tries to save an invalid entity back to
> > the database. I will have to think on your suggestion a bit more before
> > I am sure however.
> As a general rule, every function should return one "kind" of thing.
> Notice I don't say "type", because it doesn't matter what the type/class
> of the data is, so long as it is conceptually the same sort of result.
> E.g. a function that opens a connection to a database should *only*
> return a connection to a data, although the actual type of that
> connection may differ depending on the database. It shouldn't return
> either a connection or an error code.
> I say that this is a general rule, because you can get away with breaking
> it, sometimes. E.g. string.find() returns either an offset or an error
> signal of -1. But note that this sometimes leads to bugs where people
> forget to check for a result of -1, and end up with code doing something
> You've suggested a usage:
> "The list of validation error descriptions is returned instead of
> raising exceptions so clients can show the errors to the user for
> But you can do that with an exception as well:
> while True:
> validate(arguments) # returns None on success, or raise Failure
> except Failure, e:
> print e.msg
> for error in e.errors:
> print "You must fix this error: %s" % error
> # when we exit the loop, the arguments are validated.
> If you're coming from a Java background, you may be concerned that
> exceptions are expensive. They aren't. Setting up the try...except block
> is very cheap. There's very little overhead to a try block that doesn't
I'm coming from a .Net background, and yes, one of the reasons I did
not consider raising exceptions was to avoid the overhead of an
exception handler clause, which in .Net land is expensive.
some more thought on this:
If I were going to be checking for validity during a property setter,
I would probably raise an exception there, because the essence of what
a client was requesting is "set property", and an invalid value
precludes this action from happening.
However, hoping to make client code cleaner and to avoid setter
functions doing expensive db lookup validations, I do not validate
during the setter, but instead defer it until the client explicitly
asks for the validity of the business object. So the essence of the
client's request at that point is "what are the invalid values for the
object", and an exception should only be raised if there was something
stopping this request from being served. Invalid business object
field values do not stop the functionality of the invalid() method.
If I had a validation function that checked the db for a duplicate
primary key, then the invalid() function should raise an exception if
the db could not be contacted. A client should be on the lookout for
that type of exception, but to throw a bunch of exceptions back at a
client who simply requested a list of things that need to be fixed
seems heavy. We would essentially be using Exceptions as an expected
return value of a function. So a doc string would explain: "Returns
None for a valid object, and Exceptions for an invalid object."
Should exceptions be an expected "return value" from a function? Am I
still using my .Net brain?
More information about the Python-list