What is the recommended structure to write validate functions with many conditions? See these two examples. The first looks ugly, the second isn't very common, perhaps because assert
is generally used to rule out unexpected behaviour. Are there better alternatives?
def validate(val):
if cond1(val):
return False
if cond2(val):
return False
if cond3(val)
return False
return True
Or
def validate(val):
try:
assert cond1(val)
assert cond2(val)
assert cond3(val)
return True
except AssertionError:
return False
The first way is much better. It can be prettified a little bit using
any()
:A compact way to write that function is to use
any
and a generator expression:The
any
andall
functions short-circuit, so they'll stop testing as soon as they have a definite result, i.e.,any
stops as soon as it hits a True-ish value,all
stops as soon as it hits a False-ish value, so this form of testing is quite efficient.I should also mention that it's much more efficient to pass a generator expression like this to
all
/any
than a list comprehension. Becauseall
/any
stop testing as soon as they get a valid result, if you feed them from a generator then the generator will stop too, thus in the above code ifcond(val)
evaluates to a True-ish value no further conditions will be tested. But if you passall
/any
a list comprehension, egany([cond(val) for cond in conditions])
the whole list has to be be built beforeall
/any
can even start testing.You haven't shown us the internal structure of your
cond
functions, but you did mentionassert
in your question, so I feel that the following remarks are in order here.As I mentioned in the comments,
assert
should not be used to validate data, it's used to validate program logic. (Also, assertion-handling can be disabled via an -O command line option). The correct Exception to use for data with invalid values isValueError
, and for objects that are the wrong type, useTypeError
. But bear in mind that exceptions are designed to handle situations that are exceptional.If you expect a lot of malformed data then it's generally more efficient to use
if
based logic than exceptions. Python exception-handling is quite fast if the exception isn't actually raised, in fact it's faster than the equivalentif
based code. However, if the exception is raised say more than 5-10% of the time, then thetry...except
based code will be noticeably slower than theif
based equivalent.Of course, sometimes using exceptions is the only sensible option, even though the situation isn't all that exceptional. A classic example is when you're converting a collection of numeric strings to actual numeric objects, so that strings that represent integers get converted to integer objects, other numeric strings get converted to floats, and other strings get left as strings. The standard way to do this in Python involves using exceptions. For example:
output
Using "Look Before You Leap" logic here is possible here, but it makes the code more complicated because you need to deal with possible minus signs and scientific notation.
and
operator exhibits "short-circuit" behavior in Python.Depending on your intent I find the cleanest way is to return the result of
and
or ''or'' checks on each of your conditions.Or, to reverse this (as in your example):