Formatting strings with "{0: d}" does not convert to an integer

This is about the same problem as in this swimming question .

If you have a value that can be converted to an integer, the old %d will convert it, but the format does not work.

 class MyIntegerTenClass: def __int__(self): return 10 def __str__(self): return 'ten' ten = MyIntegerTenClass() print '%d, %02X, %s' % (ten, ten, ten) # ok print '{0}'.format(ten) # ok print '{0:d}, {0:02X}'.format(ten) # ValueError: Unknown format code 'd' for object of type 'str' 

Is there a way to change the format behavior without touching the class of the formatted value (without adding the __format__ method to this class)?

Edit: My goal is to get formatting depending on the format string, but not on the value. Therefore, if "d" or "x" is specified in the format string, convert the value to int and then to decimal or hexadecimal. If the format string says "s", convert it to a string directly. As the old % did.

In fact, I could even add the __format__ method to the value class. But how can I check in this method if the specified format specification is an integer format specification? Without overriding the parser of the embedded format format.

Edit: Here is a solution with __format__ and exceptions. Any better ideas?

 class MyIntegerTenClass: def __int__(self): return 10 def __str__(self): return 'ten' def __format__(self, spec): fmt = '{0:%s}'%spec try: return fmt.format(str(self)) except: return fmt.format(int(self)) ten = MyIntegerTenClass() print '%d, %02X, %s' % (ten, ten, ten) # ok, prints "10, 0A, ten" print '{0:d}, {0:02X}, {0}'.format(ten) # ok, prints "10, 0A, ten" 
+6
source share
3 answers

The first approach to this problem might be just try it:

 class MyIntegerTenClass: def __int__(self): return 10 def __str__(self): return 'ten' def __format__(self, format_spec): try: s = format(str(self), format_spec) except ValueError: s = format(int(self), format_spec) return s 

If MyIntegerTenClass can be inserted into a format string as a string, it will. If not, it will be converted to int and resubmitted to format .

 >>> print '{0}, {0:s}, {0:d}, {0:02X}, {0:f}'.format(ten) ten, ten, 10, 0A, 10.000000 

If you want the default view to be 10 instead of ten , you only need to replace the conversion strings:

  def __format__(self, format_spec): try: s = format(int(self), format_spec) except ValueError: s = format(str(self), format_spec) return s 

Test output:

 >>> print '{0}, {0:s}, {0:d}, {0:02X}, {0:f}'.format(ten) 10, ten, 10, 0A, 10.000000 

As a complement, I do not believe that you can get the right behavior without defining __format__ ; however, you can develop a more complex approach using the Formatter object. However, I think the exception-based approach gives you many built-in functions for free.

0
source

pass an integer instead of a string, and it will work fine.

 >>> print '{0:d}'.format(1) 1 >>> print '{0:d}'.format('1') Traceback (most recent call last): File "<pyshell#57>", line 1, in <module> print '{0:d}'.format('1') ValueError: Unknown format code 'd' for object of type 'str' 
+1
source

It says ten is a string, you are trying to format it as a number.

Try wrapping it in a cast:

 >>> print '{0:d}, {0:02X}'.format(int(ten)) 10, 0A 
0
source

Source: https://habr.com/ru/post/920357/


All Articles