Подтвердить что ты не робот

Использование .format() для форматирования списка с аргументами ширины поля

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

Учитывая

res = ['Irene Adler', 35,  24.798]

и

(1) print('{0[0]:10s} {0[1]:5d} {0[2]:.2f}'.format(res))
(2) print('{:{}s} {:{}d} {:{}f}'.format(res[0], 10, res[1], 5, res[2], .2))

отлично работают и оба печатаются:

Irene Adler    35 24.80
Irene Adler    35 24.80

Я не знал, что могу заниматься списками, как в (1), который является опрятным. я ранее видели аргументы ширины поля (2) со старым форматированием %.

Мой вопрос о желании сделать что-то вроде этого, которое сочетает (1) и (2):

(3) print('{0[0]:{}s} {0[1]:{}d} {0[2]:{}f}'.format(res, 10, 5, .2))

Однако я не могу этого сделать, и я не смог выяснить из документации, если это возможно. Было бы хорошо просто поставьте список для печати и аргументы для ширины.

Кстати, я тоже пробовал это (без удачи):
args = (10, 5, .2)
(4) print('{0[0]:{}s} {0[1]:{}d} {0[2]:{}f}'.format(res, args))

В обоих случаях я получил:

D:\Users\blabla\Desktop>python tmp.py
Traceback (most recent call last):
  File "tmp.py", line 27, in <module>
    print('{0[0]:{}s} {0[1]:{}d} {0[2]:{}f}'.format(res, 10, 5, .2))
ValueError: cannot switch from manual field specification to automatic field numbering

D:\Users\blabla\Desktop>python tmp.py
Traceback (most recent call last):
  File "tmp.py", line 35, in <module>
    print('{0[0]:{}s} {0[1]:{}d} {0[2]:{}f}'.format(res, args))
ValueError: cannot switch from manual field specification to automatic field numbering

Я также попытался использовать zip() для объединения двух последовательностей без удачи.

Мой вопрос:

Могу ли я указать список, который будет напечатан эффективно, делая то, что я пытался безуспешно (3) и (4) (ясно, если это возможно, я не используя правильный синтаксис), и если да, то как?

4b9b3361

Ответ 1

Сообщение об ошибке

ValueError: cannot switch from manual field specification to automatic field numbering

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

print('{0[0]:{1}s} {0[1]:{2}d} {0[2]:{3}f}'.format(res, 10, 5, .2))

отлично работает.

Ответ 2

Если вы хотите использовать .format(res, args), вы можете указать все индексы в строке формата следующим образом:

>>> print('{0[0]:{1[0]}s} {0[1]:{1[1]}d} {0[2]:{1[2]}f}'.format(res, args))
Irene Adler    35 24.80

Но если вы хотите сделать строку формата без индексов, вы можете создать кортеж последовательных пар (res[0], args[0], ... , res[-1], args[-1]).

Это делается по этой идиоме:

>>> sum(zip(res, args), ())
('Irene Adler', 10, 35, 5, 24.798, 0.2)

Теперь вы можете передать это в упрощенную строку формата (через * -argument):

>>> fmt = sum(zip(res, args), ())
>>> print('{:{}s} {:{}d} {:{}f}'.format(*fmt))
('Irene Adler', 10, 35, 5, 24.798, 0.2)

Это можно сделать, конечно, в одной строке:

>>> print('{:{}s} {:{}d} {:{}f}'.format(*sum(zip(res, args), ())))
Irene Adler    35 24.80

Чтобы сделать его читаемым, я бы назвал преобразование:

def flat_pairs(iterable1, iterable2):
    return sum(zip(iterable1, iterable2), ())

# (...)

>>> print('{:{}s} {:{}d} {:{}f}'.format(*flat_pairs(res, args)))
Irene Adler    35 24.80

Я думаю, что последний из них - разумный компромисс между читабельностью, удобством и, конечно же, демонстрирующим ваш питонический образ мышления, который является основной мотивацией для игры с такими вещами.