Assume that I wish to perform an action on a string (e.g., print the string) if, and only if, the string first passes several tests. The tests are diverse (and may even be complex functions themselves), and passing a test may mean different things depending on the specific test. For example, some tests can be discretized to result in True/False. Other tests are considered passed if the underlying function doesn't raise an exception.Moreover, assume that I wish to have all tests (there may be dozens of them!) combined in a single custom function (e.g., validate_string).My objective is to write code (i.e., a combination of validate_string() and main()) that works off test after test and only prints the string if none of the tests in validate_string() fails.One could naively imagine utilizing a custom function that employs exception handling to simply break the script if any of the tests in function validate_string() fails. That way the code exits before the print command in main() is executed. However, to me such a design misuses exception handling and I would prefer a different design.def validate_string(my_string, required_end):    try:        if not my_string[-1] == required_end:            raise ValueError    except ValueError:        exit('ERROR: String `%s` does not end with `%s`.' % (my_string, required_end))    try:        complex_function(my_string)    except:        exit('ERROR: String `%s` could not be processed.' % (my_string))def main(my_string):    validate_string(my_string, o)    print my_string> main(foo bar)ERROR: String `foo bar` does not end with `o`.Can anybody recommend a better overall design for this type of problem?
Design of multi-test function to validate a string
design;python;programming practices;exceptions;functions
Regardless of how this is implemented, you haven't been very clear about the behavior you want.My objective is to write code (i.e., a combination of validate_string() and main()) that works off test after test and only prints the string if none of the tests in validate_string() fails.This is simple enough to achive. But what should happen when a test fails? Do you want to know why it didn't print? If not this isn't validation. This is filtering. 80% of the work here isn't when this passes. It's when it doesn't.One could naively imagine utilizing a custom function that employs exception handling to simply break the script if any of the tests in function validate_string() fails. That way the code exits before the print command in main() is executed. However, to me such a design misuses exception handling and I would prefer a different design.No, that's not a misue of exception handling. That's not handling exceptions. Exeception handling is when you catch an exception and recover from it. You close any opened resources and put the system back into a useable state. Likely you'll want to log the exception so people can debug the system. You may also need to notify the user of what happened so they stop waiting for something to happen.Not handling an exception means the program is going to terminate. That also may be what you want. Terminating when an exception happens ensures the system doesn't go into a weird state and start destroying things you care about.You need to decide what should happen when the string is invalid. By calling your method validate_string() you make it seem like something bad has happened when it fails. If all you want is for the system to queitly not print the invalid string and then go about the rest of it's business as if nothing was ever wrong then your string isn't invalid, it's filtered. filter_string() would be a better name.The tests are diverse (and may even be complex functions themselves), and passing a test may mean different things depending on the specific test. For example, some tests can be discretized to result in True/False. Other tests are considered passed if the underlying function doesn't raise an exception.The tests may be diverse but we need to make them consistent one way or another to work with them. You can do that by either rewriting the tests or wrapping the tests that need it in something that makes them consistent.If we make them all return a bool when the execption is something we want to recover from this works:def printValidString(str, predicate_list):  if all(f(str) for f in predicate_list):    print strThis will only print if all checks pass. Any unhandled exection will blow right out of that and cause us to terminate. Any handled exception can be turned into a false and supress the printing.def isSunny(mayThrow, args):  try:    mayThrow(args)    return True  except ExceptionTypeWeHandle:    return FalseWhy is this an ok design? Because the prohibition against using exceptions to branch is about if else being better.  If else doesn't work when moving through contexts.Is this an awesome design? No. It would be much better to have consistant checks from the start and use them, well, consistantly. But presuming you're stuck with inconsistant checks, wrapping them to make them consistant works.Under this design there are three posible outcomes. Every check passes, the string is printed, and execution continuesA check fails in an expected way, the string is not printed, and execution continuesa check returned false on it's ownisSunny() ran a check, handled an expected exception, and returned falseA check fails in an unexpected way, the string is not printed, and execution is halted after the unexpected exception bubbles up the call stackIs something like that what you had in mind?