Using .format() to format a list with field width arguments
Solution 1:
The error message
ValueError: cannot switch from manual field specification to automatic field numbering
pretty much says it all: You need to give explicit field indices everwhere, and
print('{0[0]:{1}s} {0[1]:{2}d} {0[2]:{3}f}'.format(res, 10, 5, .2))
works fine.
Solution 2:
If you want to use .format(res, args)
, you can specify all indices in the format string like that:
>>> print('{0[0]:{1[0]}s} {0[1]:{1[1]}d} {0[2]:{1[2]}f}'.format(res, args))
Irene Adler 35 24.80
But, if you want to make the format string without indices, you can create a tuple of consecutive pairs (res[0], args[0], ... , res[-1], args[-1])
.
This is done by this idiom:
>>> sum(zip(res, args), ())
('Irene Adler', 10, 35, 5, 24.798, 0.2)
You can now pass this into a simplified format string (via *
-argument):
>>> fmt = sum(zip(res, args), ())
>>> print('{:{}s} {:{}d} {:{}f}'.format(*fmt))
('Irene Adler', 10, 35, 5, 24.798, 0.2)
This can, of course, be done on one line:
>>> print('{:{}s} {:{}d} {:{}f}'.format(*sum(zip(res, args), ())))
Irene Adler 35 24.80
To make it readable, I would name the transformation:
def flat_pairs(iterable1, iterable2):
return sum(zip(iterable1, iterable2), ())
# (...)
>>> print('{:{}s} {:{}d} {:{}f}'.format(*flat_pairs(res, args)))
Irene Adler 35 24.80
I think the last one is a reasonable trade-off between readability, convenience, and of course - showing off your Pythonic way of thinking, which is the primary motivation for playing with such stuff.