9

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.

4
  • It seems like using an explicit if-else is the most straightforward way... This is the problem you get when you deal with mixed types, and why you should avoid it when possible. Commented Apr 18, 2017 at 22:47
  • @juanpa.arrivillaga: I just though that I missed a switch in .format() or something - to me it seems that this would be a problem people likely run into quite frequently and hence there might be something built-in already... Commented Apr 18, 2017 at 23:06
  • May I ask, why is it even possible that you get either a float or the string "n/a"? It seems that is the real problem. Commented Apr 18, 2017 at 23:08
  • @juanpa.arrivillaga Well, that's the input data I am working with. Technically speaking, I convert the numbers from string to float first, of course, but I omitted this from the question as it seems not immediately relevant to the problem of formatting. Commented Apr 18, 2017 at 23:29

3 Answers 3

7

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 
Sign up to request clarification or add additional context in comments.

Comments

4

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() 

1 Comment

This is what I ended using in the end - converting the "n/a"-value to "nan".
1

maybe something like this

str = "{0:.2f}".format(var) if isinstance(var, float) else var print(str) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.