Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

format value that could be number and/or string in python 3

Is there a concise way of formatting a number, that on occasion can also be a string?

The number would normally be a float, but occasionally it's also denoted as the string "n/a".

I would like to format the float with a fixed number of decimals, but print the entire string in case it is not a number.

For instance:

var=3.145623
print("This is {0:.2f}".format(var))

>>>This is 3.14

,but

var = "n/a"
print("This is {0:.2f}".format(var))

>>> File "<stdin>", line 1, in <module>
>>> ValueError: Unknown format code 'f' for object of type 'str'

I am not surprised by the ValueError, but wonder if there is a concise way around it, ideally without an explicit if-statement.

like image 221
Gerhard Avatar asked Apr 18 '17 22:04

Gerhard


2 Answers

Indeed, the f format specifier only works on actual float values. You can't avoid having to special-case your n/a value.

You can format the float separately, and conditionally, then interpolate the result into the larger template:

var_formatted = format(var, '.2f') if var != 'n/a' else var
print("This is {0:4}".format(var_formatted))

If you are really averse to if, you can use exception handling too:

try:
    var_formatted = format(var, '.2f')
except ValueError:
    var_formatted = 'n/a'
print("This is {0:4}".format(var_formatted))

Another option would be for you to wrap the value in a class with a __format__ method:

class OptionalFloat(object):
    def __init__(self, value):
        self.value = value
    def __format__(self, fmt):
        try:
            return self.value.__format__(fmt)
        except ValueError:
            return self.value

print("This is {0:.2f}".format(OptionalFloat(var)))

This moves the requirement to detect the type into another class method, keeping your output code a little cleaner and free of all those pesky conditionals or exception handlers:

>>> var = 3.145623
>>> print("This is {0:.2f}".format(OptionalFloat(var)))
This is 3.15
>>> var = 'n/a'
>>> print("This is {0:.2f}".format(OptionalFloat(var)))
This is n/a
like image 143
Martijn Pieters Avatar answered Nov 03 '22 15:11

Martijn Pieters


Python supports not-a-number as float('nan') and it may be more useful than the string "n/a" in your code. It works with formatting and produces more sane results than a string if you use it in computations.

NaN:

>>> n = float('nan')
>>> n
nan
>>> "{0:.2f}".format(n)
'nan'
>>> n == 3
False
>>> n * 2
nan
>>> n < 5
False

String:

>>> n = 'n/a'
>>> "{0:.2f}".format(n)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Unknown format code 'f' for object of type 'str'
>>> n == 3
False
>>> n * 2
'n/an/a'
>>> n < 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: str() < int()
like image 41
tdelaney Avatar answered Nov 03 '22 15:11

tdelaney