web-dev-qa-db-fra.com

Utilisation de .format () pour formater une liste avec des arguments de largeur de champ

J'ai récemment (enfin?) Commencé à utiliser .format() et j'ai peut-être une question un peu obscure à ce sujet.

Donné

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

et

(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))

fonctionne très bien et les deux imprimés:

Irene Adler    35 24.80
Irene Adler    35 24.80

Je ne savais pas que je pouvais traiter des listes comme dans (1), ce qui est bien. J'avais déjà vu des arguments de largeur de champ (2) avec l'ancien formatage % Auparavant.

Ma question est de vouloir faire quelque chose comme ça qui combine (1) et (2):

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

Cependant, je ne suis pas en mesure de le faire, et je n'ai pas été en mesure de comprendre à partir de la documentation si cela était possible. Ce serait bien de fournir la liste à imprimer et les arguments pour la largeur.

Au fait, j'ai aussi essayé ça (sans chance):

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

Dans les deux cas, j'ai obtenu:

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

J'ai également essayé d'utiliser Zip() pour combiner les deux séquences sans succès.

Ma question est:

Puis-je spécifier une liste à imprimer efficacement en faisant ce que j'essayais de faire sans succès dans (3) et (4) (clairement si c'est possible, je n'utilise pas la bonne syntaxe) et si oui, comment?

46
Levon

Le message d'erreur

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

dit à peu près tout: vous devez donner des indices de champ explicites partout, et

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

fonctionne bien.

63
Sven Marnach

Si vous souhaitez utiliser .format(res, args), vous pouvez spécifier tous les index dans la chaîne de format comme ceci:

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

Mais, si vous souhaitez créer la chaîne de format sans index, vous pouvez créer un Tuple de paires consécutives (res[0], args[0], ... , res[-1], args[-1]).

Cela se fait par cet idiome:

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

Vous pouvez maintenant le passer dans une chaîne de format simplifiée (via *-argument):

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

Cela peut, bien sûr, se faire sur une seule ligne:

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

Pour le rendre lisible, je nommerais la 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

Je pense que le dernier est un compromis raisonnable entre la lisibilité, la commodité et bien sûr - montrant votre façon de penser Pythonic, qui est la principale motivation pour jouer avec de telles choses.

2
Tomasz Gandor