Пустой числовой тип в спецификатор формата - PullRequest
2 голосов
/ 13 февраля 2012

Есть ли способ передать "пустой" числовой тип в спецификатор числового формата и распечатать пустое пространство, связанное с этим спецификатором?

т.

n = "Scientific:"
v = 123.321
strfmt = "%5.4E"
output = "%s|"+strfmt+"|"
print output % (n, v)

>   Scientific:|1.2332E+02|

v = EMPTY
print output % (n, v)

>   Scientific:|          |

Конечная цель - справиться с неполными строками без адаптивного изменения строки формата во время цикла

perline = 3
n = ["1st:","2nd:","3rd:","4th:","5th:","6th:"]
v = [1.0, 2.0, 3.0, 4.0]

strfmt = "%5.4E"
output = ("%s|"+strfmt+"|  ")*perline+"\n"

for args in map(EMPTY,*[iter(n),iter(v)]*perline):
    print output % args

>   1st:|1.0000E+00|  2nd:|2.0000E+00|  3rd:|3.0000E+00|
>   4th:|4.0000E+00|  5th:|          |  6th:|          |

Чтобы выполнить приведенный выше код, я заменил EMPTY на None, хотя это дает ошибку, когда вы передаете None в строку формата

Ответы [ 6 ]

0 голосов
/ 16 февраля 2012

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

Существует несколько способов обойти это, как показано ниже.Лично мне понравились части ответа Unutbu.Я думаю, что в конечном итоге я создам два спецификатора формата и использую логику, предложенную Blender.

0 голосов
/ 13 февраля 2012

Как предложено выше, просто преобразуйте свои числа в строки перед печатью и замените пропущенные числа пустыми строками одинаковой длины. Это может быть написано очень компактно, однако я бы никогда не использовал это в серьезном коде:

from itertools import izip_longest, groupby, chain

perline = 3
n = ["1st:","2nd:","3rd:","4th:","5th:","6th:"]
v = [1.0, 2.0, 3.0, 4.0]

strfmt = "%5.4E"
output = ("%s|%s|  ")*perline

for _, args in groupby(enumerate(chain(*izip_longest(n, (strfmt % x for x in v),
                                                     fillvalue = ' '*len(strfmt % 0)))),
                       lambda (i, v): i/perline/2):
    print output % zip(*args)[1]

Более читаемая и надежная версия последнего цикла:

l = ()
for pair in izip_longest(n, (strfmt % x for x in v),
                         fillvalue = ' '*len(strfmt % 0)):
    l += pair
    if len(l) == perline*2:
        print output % l
        l = ()
0 голосов
/ 13 февраля 2012

Вы можете использовать itertools.izip_longest, чтобы связать элементы в n и v и заполнить пропущенные значения пустой строкой.

Чтобы получить правильное форматирование для элементов в v, вы можете предварительно отформатировать поплавки с помощью strfmt и использовать что-то вроде

output = "%s|%10s|  "

чтобы объединить предметы в n и v. Таким образом, элементы в v теперь являются строками, включая пустые строки, а не смесью чисел с плавающей точкой и пустых строк.


import itertools

perline = 3
n = ["1st:", "2nd:", "3rd:", "4th:", "5th:", "6th:"]
v = [1.0, 2.0, 3.0, 4.0]

strfmt = "%5.4E"
v = (strfmt % val for val in v)
output = "%s|%10s|  "

pairs = itertools.izip_longest(n, v, fillvalue = '')
items = (output % (place, val) for place, val in pairs)
for row in zip(*[items]*perline):
    print(''.join(row))

выходы

1st:|1.0000E+00|  2nd:|2.0000E+00|  3rd:|3.0000E+00|  
4th:|4.0000E+00|  5th:|          |  6th:|          |  
0 голосов
/ 13 февраля 2012

Краткий ответ: для поля n шириной позиции подойдет '% n s'% ''.То есть на '%15s' % '' будет напечатано 15 пробелов.

Длинный ответ: при указании ширины в спецификаторах формата первое число является минимальной шириной поля целого ."%5.4E" займёт более 5 мест, потому что только экспонента займет уже 3 места.

Укажите что-то вроде "%12.4E" и получите согласованные результаты.Для пропущенных значений укажите "%12s" и передайте пустую строку (не None) вместо значения.

0 голосов
/ 13 февраля 2012

Один из вариантов - заменить числовой формат в output на %s, а затем в заменяющем кортеже создать либо правильный числовой вывод, либо пустое пространство, в зависимости от того, что v:

>>> v = 123.321
>>> "%s|%s|" % (n, "%5.4E" % v if v is not None else " "*10)
'Scientific:|1.2332E+02|'
>>> v = None
>>> "%s|%s|" % (n, "%5.4E" % v if v is not None else " "*10)
'Scientific:|          |'

Вы можете сделать это немного более функциональным с помощью простого замыкания:

def make_default_blank_formatter(format, default):
    def default_blank_formatter(v):
        return format % v if v is not None else default
    return default_blank_formatter

scientific_formatter = make_default_blank_formatter("%5.4E", " "*10)

>>> v = 123.321
>>> "%s|%s|" % (n, scientific_formatter(v))
'Scientific:|1.2332E+02|'
>>> v = None
>>> "%s|%s|" % (n, scientific_formatter(v))
'Scientific:|          |'

edit: Вот как вы можете переделать свой код печати, чтобы использовать это:

perline = 3
n = ["1st:","2nd:","3rd:","4th:","5th:","6th:"]
v = [1.0, 2.0, 3.0, 4.0, None, None]

strfmt = "%5.4E"
output = ("%s|%s|  ")*perline

for args in zip(*[iter(n),iter(map(scientific_formatter, v))]*perline):
    print output % args
0 голосов
/ 13 февраля 2012

Вы не сможете сделать это с помощью простого форматирования чисел.Вам понадобится немного логики:

strfmt = "%5.4E"
v = None

if v in [None, '']:
  output = "%s|          |"
else:
  output = "%s|"+strfmt+"|"
...