Форматирование строк с помощью " {0:d}" не преобразуется в целое число

это примерно та же проблема, что и в этот вопрос о поплавках.

когда у вас есть значение, которое может быть преобразовано в целое число, старый %d преобразует его, но формат не делает.

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'

есть ли способ изменить поведение формата, не касаясь класса значения, которое будет отформатировано (без добавления __format__ метод этого класса)?

Edit: моя цель - получить форматирование в зависимости от формата string, но не на значение. Поэтому, если строка формата говорит "d" или "x", преобразуйте значение в int, а затем в десятичное или шестнадцатеричное представление. Если строка формата говорит "s", преобразуйте ее в строку напрямую. Как старый % сделал.

на самом деле, я мог бы даже добавить __format__ метод для класса значения. Но как проверить в этом методе, является ли данная спецификация формата спецификацией целочисленного формата? Без переопределения синтаксического анализатора спецификации формата встроенный формат.

Edit: вот решение с __format__ и исключения. Есть идеи получше?

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"

3 ответов


первый подход к этой проблеме может быть просто try это:

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

если MyIntegerTenClass можете будет вставлен в строку формата в виде строки, это будет. Если нет, он будет преобразован в int и повторно отправлен в format.

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

если вы хотите, чтобы представление по умолчанию 10 вместо ten, вам нужно только поменять линии преобразования:

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

проверить выход:

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

как добавление, я не верю, что вы сможете получить желаемое поведение без определения __format__, однако, вы можете разработать более сложный подход с использованием Formatter


передайте целое число вместо строки, и оно будет работать нормально.

>>> 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'

Он говорит, что десять-это строка, вы пытаетесь отформатировать ее как число.

попробуйте обернуть его в cast:

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