This is about the same issue as in this question about floats.
When you've got a value that could get converted to an integer, the old %d
would convert it, but format doesn't.
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 modify the behaviour of format, without touching the class of the value to be formatted (without adding a __format__
method to that class)?
Edit: My goal is to get the formatting dependent on the format string, but not on the value.
So if the format string says "d" or "x", convert the value to int and then to decimal or hexadecimal representation.
If the format string says "s", convert it to string directly. As the old %
did.
Actually, I could even add a __format__
method to the class of the value. But how do I check, in that method, if the given format specification is an integer format specification? Without reimplementing the format specification parser of the builtin format.
Edit: Here's 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"
The %d operator is used as a placeholder to specify integer values, decimals, or numbers. It allows us to print numbers within strings or other values. The %d operator is put where the integer is to be specified. Floating-point numbers are converted automatically to decimal values.
They are used for formatting strings. %s acts a placeholder for a string while %d acts as a placeholder for a number. Their associated values are passed in via a tuple using the % operator.
For example, "print %d" % (3.78) # This would output 3 num1 = 5 num2 = 10 "%d + %d is equal to %d" % (num1, num2, num1 + num2) # This would output # 5 + 10 is equal to 15. The %f formatter is used to input float values, or numbers with values after the decimal place.
%r is not a valid placeholder in the str. format() formatting operations; it only works in old-style % string formatting. It indeed converts the object to a representation through the repr() function.
A first approach to this problem might be simply to 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 the format string as a string, it will be. If not, it will be converted into an 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 representation to be 10
instead of ten
, you need only swap the conversion lines:
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 an addendum, I don't believe you'll be able to get the behavior you want without defining __format__
; however, you can develop a more sophisticated approach using a Formatter
object. Still, I think the exception-based approach gives you a lot of built-in functionality for free.
pass an integer instead of a string and it'll 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'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With