-2
    try:
        return float(x)
    except:
        return 0

So this function uses the try except statement but is there an alternative way of doing this??

Tiger
  • 5
  • 1
  • 4
  • 2
    What sort of alternative are you looking for? – JRiggles May 05 '22 at 17:18
  • Could you provide more detail on what type of variable x is? – notoriousjere May 05 '22 at 17:18
  • 2
    This looks perfectly fine. You could improve it by catching a specific exception like `except ValueError`. – ForceBru May 05 '22 at 17:19
  • You could use https://docs.python.org/3/library/contextlib.html#contextlib.suppress in some cases. – jonrsharpe May 05 '22 at 17:23
  • Override the float class /: – Deepak Tripathi May 05 '22 at 17:27
  • Returning 0 is potentially ambiguous. Surely you'd want to know if *x* was a valid string representation of a (potentially) floating point number. Of course you may want zero as default in which case your code is fine (notwithstanding the unqualified *except* clause). Personally I would either allow the exception to propagate or return None - but that's very much a matter of opinion – DarkKnight May 05 '22 at 17:32

5 Answers5

0

Try/except seems like to simplest and best solution, but you could use an if statement similar to this:

if str(x).lstrip('-').replace('.', '', 1).isdigit():
    return float(x)
return 0

The if statement will remove - if it's a negative number and exactly one . from the input and then check there is only digits left. It converts it to a string first so we can use .replace().

There are still possibilities of exceptions like mentioned in the comments if x == '²'

Mikael Kjær
  • 670
  • 3
  • 6
  • This may not be reliable. Consider what happens when *x == '-1.5'* The decimal point would be removed and isdigit() would return False yet *float('-1.5')* is perfectly legal – DarkKnight May 05 '22 at 17:28
  • ...and on the other hand, this code can still raise an exception, e.g. when `x == '²'` – trincot May 05 '22 at 17:32
  • Good points. I added an `lstrip` to take care of negative numbers, but I don't see any way of taking care of unlikely inputs like `x == '²'` without try/except. – Mikael Kjær May 05 '22 at 17:39
0

Your code looks like it would work but I would always make sure to define the exception you are trying to catch. In this case ValueError
Another way to write this would be

def func(x):
    try:
        y = float(x)
    except ValueError:
        return 0
    # do some more with y if it was changed to a float
    return y
Cai Allin
  • 307
  • 2
  • 11
0

Assuming x is a str, you could use regex to see if that str is formatted properly to be cast as a float.

import re

float_regex = re.compile(r"^-?(\d*\.)?\d+$")

if float_regex.match(x):
    return float(x)
return 0
  • The ^ ... $ at beginning and end ensure that the match isn't a substring and that the full string can only contain the inner regex. The string must start and stop exactly as defined.
  • -? allows an optional minus sign
  • (\d*\.)? optionally allows a digit followed by a decimal
  • \d+ requires at least 1 digit

See here for more details on the regex expression used: https://regex101.com/r/3RXmM1/1

All of this being said, use your original code, except make sure you only catch the ValueError exception. Using regex is overkill here unless you have a specific reason. If python can't cast as a float then just let it do the work for you.

  • There are other formats for floats, like scientific notation and "inf", "nan", ...etc. Also an ending point is allowed: `3.` ... and more. – trincot May 05 '22 at 17:33
  • @trincot yeah I mean it depends how many bases you want to cover. I still think the try/except is the best option and it's certainly what I'd use. – notoriousjere May 05 '22 at 17:35
  • See here as well for more discussion: https://stackoverflow.com/questions/12643009/regular-expression-for-floating-point-numbers – notoriousjere May 05 '22 at 17:39
0

As @jornsharpe suggested in the comments

from contextlib import suppress
x = "abc"
res= None
with suppress(ValueError):
    res = float(x)
if not isinstance(res, float):
    res = 0
print(res) # 0

But still not a good thind to suppress the Exceptions.

Deepak Tripathi
  • 3,175
  • 1
  • 8
  • 21
0

Your code is fine; using try/catch is promoted among Python coders.

Just as an exercise, I thought I'd follow the definitions in the documentation for the float function and the lexical analysis section on floating point literals. From those we can derive the following regular expression:

import re

reFloat = re.compile(r"(?i)^\s*[+-]?(((\d(_?\d)*)?\.\d(_?\d)*|\d(_?\d)*\.?)(e[+-]?\d(_?\d)*)?|nan|inf(inity)?)\s*$")

We can then define this function:

safeFloat = lambda x, default=0: float(x) if reFloat.match(x) else default

I believe this function will call float if, and only when, float(x) would not raise an exception, provided x is a string.

Some tests:

good = ["-3.14", "10.", ".001", "+1e100", "3.14e-10", "0e0", " 3.14_15_93  ", "+NaN", "  -Infinity\n\f\r\t "]

for x in good:
    print(x.strip(), safeFloat(x))

bad = [".", "_345", "123_", "e13", "123e", "- 1", "5-3", "1e3.4", "Infinit"]

for x in bad:
    print(x.strip(), safeFloat(x))  # Always 0
trincot
  • 317,000
  • 35
  • 244
  • 286