Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unknown format code 'f' for object of type 'unicode'

Tags:

python

django

can someone tell me what is wrong with this code...

def format_money_value(num):
    return u'{0:.2f}'.format(num)

It gives me the following error:

Unknown format code 'f' for object of type 'unicode'

I'm running Django 1.5

Thank you

like image 844
MarkO Avatar asked Apr 10 '13 11:04

MarkO


3 Answers

In your case num is a unicode string, which does not support the f format modifier:

>>> '{0:.2f}'.format(u"5.0")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Unknown format code 'f' for object of type 'unicode'

You can fix the error making the conversion to float yourself:

>>> '{0:.2f}'.format(float(u"5.0"))
'5.00'

As pointed out by mgilson when you do '{0:.2f}'.format(num), the format method of the strings calls num.__format__(".2f"). This results in an error for str or unicode, because they don't know how to handle this format specifier. Note that the meaning of f is left as an implementation for the object. For numeric types it means to convert the number to a floating point string representation, but other objects may have different conventions.

If you used the % formatting operator the behaviour is different, because in that case %f calls __float__ directly to obtain a floating point representation of the object. Which means that when using %-style formatting f does have a specific meaning, which is to convert to a floating point string representation.

like image 120
Bakuriu Avatar answered Nov 07 '22 21:11

Bakuriu


what .format() do

str.format method calls __format__() method of related type. That means

<type>.__format__(<value>, <spec>)

above method accepts the same type argument as first value, and accepts a suitable spec type as second one. Like,

str.__format__('1', 's')
int.__format__(1, 'f')
float.__format__(1.00, 'f')

str.__format__ accepts any type that is derived from str type, like str or unicode. Spec value must be a valid formatter that is usable of that type. Following will raise an error

str.__format__('1', 'f')
ValueError: Unknown format code 'f' for object of type 'str'

since floating point formatting is not a suitable format type fot string. Likewise following will raise an error too

float.__format__(1.00, 's')
ValueError: Unknown format code 's' for object of type 'float'

since float is a numeric type and can not formatted as a string. But following are all valid:

float.__format__(1.00, 'g')
float.__format__(1.00, 'f')

similarly following will raise an exception

float.__format__(1.00, 'd')
ValueError: Unknown format code 'd' for object of type 'float'

since formatting a float point to a decimal value will cause precision values to be lost. But formatting an int to float will not cause a such thing, so it is a valid conversion:

int.__format__(1, 'f')

So .format() is limeted to specs that is available to the related formatting type. You must parse your value as @Bakuriu defined:

'{0:.2f}'.format(float(u"5.0"))
like image 5
FallenAngel Avatar answered Nov 07 '22 21:11

FallenAngel


The scenario where you are re-formatting a string (unicode or otherwise) as a float string is not very safe. You should first convert the string to a numeric representation and only if that succeeds should you format it as a string again. You are not in control of the data that comes into your program so you should be sure to validate it coming in.

If you choose to leave it as a string you can use this:

return u"{:.2f}".format(num) if num.isnumeric() else u"{}".format(num)

If you have already converted the string into a numeric format, you can adjust your formatter like this:

return u"{:.2f}".format(num) if isinstance(num, NumberTypes) else u"{}".format(num)
like image 1
Timothy Jannace Avatar answered Nov 07 '22 21:11

Timothy Jannace