2

I am working on a validation function. I understand that exceptions are used for errors and unexpected situations, but in the case of a validation function, if a condition is not met inside, I would expect it to return False instead of an exception.

The thing is that after the validation finishes I need to raise an message window with a message like: "Tool exited because X condition not met". My workflow has been to return tuples with the result and message:

(True, Y_message)

or (False, X_condition_not_met)

and then:

a, b = result
if not a:
    raise_window(message=b)

However recently I have stumbled upon multiple answers raising a controversy about this issue and I am confused. For example some people say to always go with exceptions: What's the best way to return multiple values from a function in Python? and others say tuples are the way to go Best practice in python for return value on error vs. success.

I would appreciate if someone could point me in the right direction.

Community
  • 1
  • 1
  • When validating, you return `False` or `True` to indicate something is valid or not. **That's not an error**, it is not an exceptional situation. You *expect* your validator to tell you if a value is valid or not. – Martijn Pieters May 26 '14 at 17:32
  • Thanks @Martijn Pieters, and what is you opinion about returning tuples? Sorry if it is not clear in my question but this was what originally got me into asking about this. – chris from local group May 26 '14 at 18:30
  • If you need to determine the message based on the value (say, an invalid value can result in one of 3 different error messages), then returning a tuple from a validator is just fine. I stuck to the terms 'valid' and 'invalid' in my answer on purpose, it doesn't matter if 'invalid' is represented by a `False` boolean or a `(False, message)` tuple, or using custom class instances, really. – Martijn Pieters May 26 '14 at 18:32
  • @Martijn Pieters I see, Would you be so kind as to add that clarification in you answer below so I could accept the answer? – chris from local group May 26 '14 at 18:39

2 Answers2

10

When validating, the purpose of your function is to tell you if the criteria are met. You expect to get a boolean result; valid or not valid. You'd only throw errors if, say, the inputs to the function are not supported, or some dependency for the validation process itself was not met. In that case, the normal operation of the validator cannot be completed, you cannot return valid or not valid in such cases because there is no way for the validator to make that determination.

You can compare this with isinstance() or issubclass(); these two functions test a value against another value. They return True or False, and raise exceptions if you give them unsupported input:

>>> isinstance(1, int)
True
>>> isinstance(1, 'foobar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types

Normal operation is validation, giving it unsupported input means no valid or invalid value can be returned and thus warrants an exception.

So, for a validator that returns either a (True, message) or a (False, message) tuple, I'd only raise exceptions if there was a problem with the validation process itself, not to indicate the (False, message) case.

Note that it doesn't matter what your validator returns; if you need to return both a valid / invalid flag and corresponding message (and only the validator can produce that message) then returning a tuple is just fine.

You could return a custom class too:

class ValidationResult(object):
    def __init__(self, result, message=''):
        self.result = bool(result)
        self.message = message

    def __nonzero__(self):  # Python 2
        return self.result

    __bool__ = __nonzero__  # Python 3

    def __str__(self):
        return self.message

then use that as a test:

valid = validation(value)
if not valid:
    raise_window(message=str(valid))
wihlke
  • 2,455
  • 1
  • 19
  • 18
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
-2

Using an exception to indicate invalid data is the idiomatic, canonical, Python solution to this problem. Consider the int() function, if you pass it invalid data, an exception occurs:

>>>> int('abc')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'abc'
Alex Gaynor
  • 14,353
  • 9
  • 63
  • 113
  • 3
    But `int()` is *not validating*. It's purpose is to **convert**, and the exception is the only way to not return a valid `int()`. A *validator* on the other hand needs to return a boolean flag: 'valid' or 'not valid'. Throwing an exception every time you could return 'not valid' instead, makes no sense. It's as if `isinstance(obj, type)` would throw an exception every time `obj` was *not* of that type. – Martijn Pieters May 26 '14 at 17:59