On Tue, Feb 5, 2013 at 3:52 PM, Steven D'Aprano
<(E-Mail Removed)> wrote:
> There's also the principle that it is best to raise an exception as early
> as possible. It's easier to track down errors at the point they are
> introduced than long afterwards.
Yes, definitely, especially (as was mentioned) if you're working with
callbacks. But I'd use isinstance then.
On Mon, Feb 4, 2013 at 9:52 PM, Steven D'Aprano
<(E-Mail Removed)> wrote:
> You seem to be making the
> classic mistake of thinking that exceptions are something to avoid:
Far from it. You've extrapolated a lot more than what I actually
said, and I completely agree with everything you wrote. I was
explaining EAFP as I see it, not advocating it for all circumstances.
Although since you bring it up, I find that the LBYL crowd tends to be
more prone to exception avoidance, e.g. returning None on a failure
rather than raising an exception, whereas the EAFP crowd seems more
likely to just let the original exception propagate up.
On Tue, 05 Feb 2013 16:20:19 +1100, Chris Angelico wrote:
> On Tue, Feb 5, 2013 at 3:52 PM, Steven D'Aprano
> <(E-Mail Removed)> wrote:
>> There's also the principle that it is best to raise an exception as
>> early as possible. It's easier to track down errors at the point they
>> are introduced than long afterwards.
> Yes, definitely, especially (as was mentioned) if you're working with
> callbacks. But I'd use isinstance then.
I'm leaning towards an isinstance check
I've been using Python since Python 1.5. Even though 1.5 had an
"isinstance" function, I learned Python from books and code written for
Python 1.4 which did not have that function, so the usual way to do type-
if type(obj) is type(1):
# it's an int
and strongly discouraged. So my instincts are still very strongly primed
to *not* do type-checking if I can avoid it. But in this case, I think I
agree with those suggesting the isinstance check is the right approach.
The main downside to this is that objects which delegate to a number will
not work unless they are explicitly registered with the Number ABC.
Thanks to everyone who responded.
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
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.
def f(n, a):
if n < 0: raise ValueError('n cannot be negative')
b = 0
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
Steven D'Aprano <(E-Mail Removed)> writes:
>> I want to check that a value is a number. [...]
> I'm leaning towards an isinstance check
Well that is the answer to your question, whether the value *is* a
number. EAFP can answer the question whether the value *behaves* like a
number, where the criterion depends on what your code is aiming to do
with the value.
BTW what if the value is Not-a-Number?
Pete Forman wrote:
> Steven D'Aprano <(E-Mail Removed)> writes:
>>> I want to check that a value is a number. [...]
>> I'm leaning towards an isinstance check
> BTW what if the value is Not-a-Number?
Nothing different, and hopefully exactly what the caller expects. As far as
Python is concerned, NANs are Numbers.
py> NAN = float('nan')
py> from numbers import Number
py> isinstance(NAN, Number)
If it's a float NAN, Python doesn't give you much control over what happens
next, but generally any arithmetic operation on a NAN will return a NAN
rather than raise.
If it's a Decimal NAN, the same applies:
py> NAN = decimal.Decimal('nan')
py> NAN + 0
If it's a Decimal SNAN (signalling NAN), then arithmetic operations signal
InvalidOperation, which by default will raise an exception: