How to parse a number as an int or float, depending on the required precision?

Requirements:

  • The input may be a string or a number
  • If the input can be interpreted as int without loss of precision, discard it in int
  • If the input can be thought of as a float, drop it into a float

Here is the code section where I use this.

def make_operand(symbol, left=None, right=None):
    valid_symbols = ['*', '/', '+', '-']
    if symbol in valid_symbols:
        return Operand(symbol, left, right)

    as_int = re.compile("^-?[0-9]+$").match(str(symbol))
    as_float = re.compile("^[-+]?[0-9]*\.?[0-9]+$").match(str(symbol))

    as_number = int(symbol) if as_int else float(symbol) if as_float else None

    if as_number:
        return NumericOperand(as_number)

    raise ValueError("Invalid symbol or number")

It works, but it looks dirty and smells bad.

An implementation using try blocks also works, but seems less simple:

    as_number = None
    try:
        as_float = float(symbol)
    except ValueError:
        as_float = None

    if as_float:
        as_int = int(as_float)
        as_number = as_int if as_int == as_float else as_float

    if as_number:
        return NumericOperand(as_number)

    raise ValueError("Invalid symbol or number")

Is there a better approach, or is one close to the Pythonic method for doing things?

+4
source share
2 answers

, C-exension, fastnumbers, . fast_real , ( coerce=True, fastnumbers>=0.7.4).

, .

>>> from fastnumbers import fast_real
>>> fast_real('56')
56
>>> fast_real('56.0')
56
>>> fast_real('56.07')
56.07
>>> fast_real('56.07 lb')
'56.07 lb'
>>> fast_real(56.07)
56.07
>>> fast_real(56.0)
56.0
>>> fast_real(56.0, coerce=True)
56
>>> fast_real(56)
56
>>> fast_real('56.07 lb', raise_on_invalid=True) 
Traceback (most recent call last):
  ...
ValueError: could not convert string to float: '56.07 lb'
+2

PEP 367 python, , __index__, . - str, :

def as_num(value):
    if isinstance(value,str):
        try:
            return int(value)
        except ValueError:
            pass #don't put return float(value) here or you will get chained exceptions
        return float(value) #this might fail and raise the error
    elif hasattr(value,"__index__"):
        return value.__index__() #possibly just int(value) if the method exists?
    else:
        return float(value) #this would fail if the object cannot be cast to a float

, , __index__ , int float , , , . if as_float if as_float is not None, symbol=0 , , :

try:
    as_float = float(symbol)
except ValueError:
    raise ValueError("Invalid symbol or number") #maybe just let the other error go instead?
else:
    if as_float.is_integer():
        return NumericOperand(int(as_float))
    return NumericOperand(as_float)
0

All Articles