isFloat: Without Exception-Handling

Jeff Epler jepler at unpythonic.net
Sat Oct 5 09:20:55 EDT 2002


On Fri, Oct 04, 2002 at 08:19:44PM -0700, Chad Netzer wrote:
> On Friday 04 October 2002 19:31, Jeff Epler wrote:
> > On Fri, Oct 04, 2002 at 06:05:19PM -0700, Chad Netzer wrote:
> 
> > > def isFloat(s):
> > >     try: return float(s) or True
> > >     except (ValueError, TypeError), e: return False
> >
> > You mean
> > def isFloat(s):
> >     try: return (float(s), True)[1]
> >     except (ValueError, TypeError), e: return False
> 
> Is there any instance when these will be different?  I assume float() will 
> always return type< float >, and so not overload the 'and'.  In which case, 
> my version doesn't have to construct a tuple (so possibly it's faster).
> 
> Just curious; for the specific case and'ing with a float, I can't think where 
> mine might go wrong (not off the top of my head, anyway).

The short-circuiting "and" and "or" operators cannot be overloaded.

For 'or', the LHS is evaluated.  If it is not false, then that is the
result of the expression.  Otherwise, the RHS is evaluated and is the
result of the expression.  So 'isFloat(math.pi) or True' will return a
non-false value, but it won't return True.

Let's compare the version with
    try: return float(s) or True # if1
          3 LOAD_GLOBAL              0 (float)
          6 LOAD_FAST                0 (s)
          9 CALL_FUNCTION            1
         12 JUMP_IF_TRUE             4 (to 19)
         15 POP_TOP             
         16 LOAD_GLOBAL              2 (True)
    >>   19 RETURN_VALUE        

to the version with
    try: # if2
      float(s)
      return True
          3 LOAD_GLOBAL              0 (float)
          6 LOAD_FAST                0 (s)
          9 CALL_FUNCTION            1
         12 POP_TOP             
         13 LOAD_GLOBAL              2 (True)
         16 RETURN_VALUE        

This second version doesn't try to be clever, but it will always return
True (never values like 'math.pi') and the code is also an instruction
shorter than your clever code above.  Of course, in the common case (s
represents a nonzero float) your version executes one less bytecode
instruction.

So, on with the timings:
[jepler at anchor jepler]$ python t.py
# function / argument / time
<function if1 at 0x401c65a4> 0.0 13.2162970304
<function if1 at 0x401c65a4> 1.0 13.1347409487
<function if2 at 0x401c63e4> 0.0 13.0910500288
<function if2 at 0x401c63e4> 1.0 13.0951679945
[jepler at anchor jepler]$ python -O t.py
# function / argument / time
<function if1 at 0x401c65a4> 0.0 12.3858759403
<function if1 at 0x401c65a4> 1.0 12.3613350391
<function if2 at 0x401c63e4> 0.0 12.4040540457
<function if2 at 0x401c63e4> 1.0 12.3739790916

Jeff




More information about the Python-list mailing list