问题
I have a python function that checks if the value passed is a valid number. The values passed are in string format.
def is_valid_numeral(text_to_check):
'''Check if passed value is a valid numeral figure'''
try:
float(text_to_check)
return True
except ValueError:
return False
A value like 6E+007
is passed and this function returns True which is correct.
After the above function, I need to save the passed figure into a Decimal field. So I run a format_decimal
function as below
def format_decimal(value, decimals):
'''Format a value to "n" decimal places
http://mkaz.com/solog/python/python-string-format.html
'''
try:
if decimals == 2:
value = int(value)/100
return "{:.2f}".format(int(value))
except ValueError:
raise
At this point, it fails with the error:
`Value Error: Invalid literal for int() with base 10:6E+007`
Since this really is a valid figure just in a different notation, is there a function that can convert this type of value for me and then pass it through the format_decimal
function?
回答1:
You're checking the validity by converting to float
, but actually doing the conversion with int
- the discrepancy is causing your problems.
The decimal
module is the best way to convert large format numbers.
>>> int(decimal.Decimal('6E+007'))
60000000
You don't want to do a double conversion to float
then int
because that can result in rounding errors.
>>> int(float('1e23'))
99999999999999991611392L
>>> int(decimal.Decimal('1e23'))
100000000000000000000000L
回答2:
Hmm. You changed the original question; the way it is now it should be trivial: since you're checking for whether float()
works now, just be consistent with that: stop using int()
! That is, change to this:
def format_decimal(value, decimals):
try:
if decimals == 2:
value = float(value)/100
return "{:.2f}".format(value)
except ValueError:
raise
But the code is still confused:
- Why are you dividing by 100? Do you really want, e.g.,
"1234"
to change into"12.34"
? - What if
decimals
isn't 2? Then yourformat_decimal()
does nothing: it "falls off the end" and so returnsNone
. - Catching an exception and immediately re-raising it is the same as not bothering to catch it to begin with. That is, the
try/except
structure, as written, does nothing except complicate the code.
It would really help if you gave exact examples of input strings and their expected output strings.
Generalizing
Try this?
def format_decimal(value, decimals=2):
from decimal import Decimal
# divide value by 10**decimals; this is just scaling
value = Decimal(value).scaleb(-decimals)
return "{:.{d}f}".format(value, d=decimals)
That allows specifying the scaling factor (decimals
). Here's sample input/output. If anything isn't what you want, say exactly what it is that you do want:
for v in "1", "1234.5678", "1.2e6":
for d in range(4):
print repr(v), d, "->", repr(format_decimal(v, d))
and the output:
'1' 0 -> '1'
'1' 1 -> '0.1'
'1' 2 -> '0.01'
'1' 3 -> '0.001'
'1234.5678' 0 -> '1235'
'1234.5678' 1 -> '123.5'
'1234.5678' 2 -> '12.35'
'1234.5678' 3 -> '1.235'
'1.2e6' 0 -> '1200000'
'1.2e6' 1 -> '120000.0'
'1.2e6' 2 -> '12000.00'
'1.2e6' 3 -> '1200.000'
回答3:
The problem is simple. 6E+007
is not an integer notation, but a float notation.
Instead of int('6E+007')
, use float first:
int(float('6E+007'))
Or, use the decimal module:
import decimal
int(decimal.Decimal('6E+007'))
Also, IMO if you want the number to have two decimal places, you should use float instead, since the value of an integer cannot contain any fractional component, and will always be like that. For example, int('1.5')
will always be 1
, not 1.5.
So just use:
value = float(value/100) #Well, i'll keep the division here,
# since i don't know what it's about.
return ":{.2f}".format(value)
Hope this helps!
来源:https://stackoverflow.com/questions/19532556/convert-6e007-into-decimal