On 2/4/2013 6:16 PM, Steven D'Aprano wrote:
The eternal conflict between "Look Before You Leap" and "Easier to Ask for
Forgiveness than Permission" (LBYL vs EAFP) continues...

A somewhat different answer is that it depends on what you want the function to do, as documented and *tested*. And that partly depends on whether it is educational code for humans, production app code, or library code.

The test driven approach would be to write tests and then do what is needed to get them to pass. Doctests, unittests, and my private function test functions allow testing for raising a particular exception. AssertRaises() is used, perhaps increasingly, in stdlib tests. The absence of any tests for the response to 'bad' input suggests that the responses are 'undefined'.

That said, I admit that Python's extensible class system makes bad-input testing harder. I also think that anyone who uses non-builtin classes outside of their intended use area has to take responsibility.

For instance:

def f(n, a):
  if n < 0: raise ValueError('n cannot be negative')
  b = 0
  while n:
    b = process(a, b)
    n -= 1

looks like a safe LBYL function. But suppose n is an instance of a class that perversely implements subtraction as addition (or as doing nothing). Algorithm termination is based on the presumption that 'decrementing' a 'positive value' moves it 'toward 0' and can only be done a finite number of times. Verifying that an input is a member of that abstract class is not trivial ;-).

> A third option is not to check x at all, and hope that it will blow
> up at some arbitrary place in the middle of my code rather than
> silently do the wrong thing.

A silent infinite loop is bad. Infinite recursion stopped with the recursion limit check is less bad.

If tests pass with no check, then nothing need be done until one moves from correctness to resource use.

--
Terry Jan Reedy

--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to