Context
I am receiving numbers as strings in Python 3 and want to transmit them as strings in order to preserve accuracy so that the upstream server can convert the numbers-as-strings to decimal.Decimal without loss of accuracy.
[Admins: I have repeatedly searched Stack Overflow and other resources can cannot find anyone asking or answering this specific question.]
Question
How do I use str.format to provide the given floating point format (below)? Showing that it's impossible is an acceptable answer.
Succinctly put, the format is just to provide at least one decimal place at all times even if that is just a trailing zero, but never to perform any rounding.
I suppose there may be a Formatter class solution, which would be acceptable if available, but a str.format solution is preferred.
I would be interested in knowing if f-strings can achieve this as well. Using f-strings is not preferred as an answer in this context, but it would be interesting to know if f-strings can provide this format (without just packing the demonstrated expression inside the f-string for execution: that's just moving the required code into a secondary evaluation environment).
Required Format
To distinguish the numbers from int the format must suffix ".0" to whole numbers only if they are presented without any decimal places, but preserve exactly any decimal places that are presented, even if that includes trailing zeroes.
There is an alternative solution under consideration which is to strip all trailing decimal places that are zeroes but leave one and only one trailing decimal zero for whole numbers (and of course preserve all non-zero decimal places without rounding).
Incoming strings can be expected to be valid int or Decimal. The special case of receiving a whole number with just the decimal point and no decimal places is invalid and will not occur (no need to handle "42."). The empty string ("") will not occur.
It's not acceptable just to configure to a large number of decimal places ("{:.28f}".format(1)).
Demonstration
AFAIK this should be the required behaviour. Looking for this behaviour using format:
for number in ("42", "4200", "42.0000", "42.34", "42.3400", "42.3456"):
string = "." in number and number or number + ".0"
print(number, "=>", string)
42 => 42.0
4200 => 4200.0
42.0000 => 42.0000
42.34 => 42.34
42.3400 => 42.3400
42.3456 => 42.3456
Alternative
This alternative behaviour is also acceptable.
for number in ("42", "4200", "42.0000", "42.34", "42.3400", "42.3456"):
string = (
number.rstrip("0")[-1] == "." and number.rstrip("0") + "0"
or "." not in number and number + ".0"
or number.rstrip("0")
)
print(number, "=>", string)
42 => 42.0
4200 => 4200.0
42.0000 => 42.0
42.34 => 42.34
42.3400 => 42.34
42.3456 => 42.3456
While your existing approaches using string manipulations are perfectly fine, if you have to use
str.format, you would have to calculate the precision you need from the number of decimal places from the given number, which can be obtained from the exponent of the number after a conversion todecimal.Decimal. Use themaxfunction to ensure a precision of at least 1:or with an f-string:
so that:
outputs:
Demo: https://ideone.com/9JbLA0
To produce the alternative output in the question, you can normalize the
Decimalobject first:This would make the test code output:
Demo: https://ideone.com/hbx3Q0