tags:

views:

240

answers:

4

I have a function that expects real numbers (either integers or floats) as its input, and I'm trying to validate this input before doing mathematical operations on it.

My first instinct is to cast inputs as floats from within a try-except block.

try:
   myinput = float(input)
except:
   raise ValueError("input is not a well-formed number")

I could also call isinstance(mydata, (float, int, long) ) but the list of "all these could be numbers" seems a bit inelegant to me.

What's the most pythonic way of going about it? Is there another option I overlooked?

+2  A: 

Maybe you can use a combination of assert and isinstance statements. Something like the following is I think a more pythonic way, as you throw an exception whenever your inputs don't follow your requirements. Unfortunately I don't see any better definition of what is a valid number than yours. Maybe someone will come with a better idea.

number = (float, int, long)
assert isinstance(mydata, (float, int, long))
Mapad
+11  A: 

To quote myself from How much input validation should I be doing on my python functions/methods?:

For calculations like sum, factorial etc, pythons built-in type checks will do fine. The calculations will end upp calling add, mul etc for the types, and if they break, they will throw the correct exception anyway. By enforcing your own checks, you may invalidate otherwise working input.

Thus, the best option is to leave the type checking up to Python. If the calculation fails, Python's type checking will give an exception, so if you do it yourself, you just duplicate code which means more work on your behalf.

Egil
I agree with this. The point about scripting languages is to not have strongly typed code. I would add that assert statement should be used more for debugging.
Mapad
I agree; if you're just going to throw an exception anyway, then why not just say "x ** y" or whatever content in the knowledge that you'll get an exception if they're not numbers?
Eli Courtwright
But then, the type of my exception depends more or less on what I do, right? For instance, abs(input) would raise a TypeError, while float(input) would raise a ValueError. Should I bother about that?
Kena
No. If you bother and throw ValueError all the time, the differentiation by python would give more information on the error.
Egil
+5  A: 

In Python 2.6 and 3.0, a type hierarchy of numeric abstract data types has been added, so you could perform your check as:

>>> import numbers
>>> isValid = isinstance(myinput , numbers.Real)

numbers.Real will match integral or float type, but not non-numeric types, or complex numbers (use numbers.Complex for that). It'll also match rational numbers , but presumably you'd want to include those as well. ie:

>>> [isinstance(x, numbers.Real) for x in [4, 4.5, "some string", 3+2j]]
[True, True, False, False]

Unfortunately, this is all in Python >=2.6, so won't be useful if you're developing for 2.5 or earlier.

Brian
+1  A: 

I don't get the question.

There are two things with wildly different semantics tossed around as "alternatives".

A type conversion is one thing. It works with any object that supports __float__, which can be quite a variety of objects, few of which are actually numeric.

try:
   myinput = float(input)
except:
   raise ValueError("input is not a well-formed number")
# at this point, input may not be numeric at all
# it may, however, have produced a numeric value

A type test is another thing. This works only with objects that are proper instances of a specific set of classes.

isinstance(input, (float, int, long) )
# at this point, input is one of a known list of numeric types

Here's the example class that responds to float, but is still not numeric.

class MyStrangeThing( object ):
    def __init__( self, aString ):
        # Some fancy parsing 
    def __float__( self ):
        # extract some numeric value from my thing

The question "real numbers (either integers or floats)" is generally irrelevant. Many things are "numeric" and can be used in a numeric operation but aren't ints or floats. For example, you may have downloaded or created a rational numbers package.

There's no point in overvalidating inputs, unless you have an algorithm that will not work with some types. These are rare, but some calculations require integers, specifically so they can do integer division and remainder operations. For those, you might want to assert that your values are ints.

S.Lott