Comment utiliser la nouvelle ligne '\ n' dans la chaîne f pour formater la sortie en Python 3.6?

109

J'aimerais savoir comment formater ce boîtier de manière pythonique avec des f-strings:

names = ['Adam', 'Bob', 'Cyril']
text = f"Winners are:\n{'\n'.join(names)}"
print(text)

Le problème est qu'il '\'ne peut pas être utilisé dans les {...}parties d'expression d'une chaîne f. Production attendue:

Winners are:
Adam
Bob
Cyril
malmené
la source
10
f"Winners are:\n{chr(10).join(names)}"
wim

Réponses:

123

Vous ne pouvez pas. Les barres obliques inverses ne peuvent pas apparaître à l'intérieur des accolades {}; cela se traduit par SyntaxError:

>>> f'{\}'
SyntaxError: f-string expression part cannot include a backslash

Ceci est spécifié dans le PEP pour les chaînes f:

Les barres obliques inverses peuvent ne pas apparaître dans les parties d'expression des chaînes f, [...]

Une option consiste à attribuer '\n'un nom, puis .joinà celui-ci dans la fchaîne -string; c'est-à-dire sans utiliser de littéral:

names = ['Adam', 'Bob', 'Cyril']
nl = '\n'
text = f"Winners are:{nl}{nl.join(names)}"
print(text)

Résulte en:

Winners are:
Adam
Bob
Cyril

Une autre option, telle que spécifiée par @wim, consiste à utiliser chr(10)pour être \nrenvoyé, puis à y rejoindre.f"Winners are:\n{chr(10).join(names)}"

Encore une autre, bien sûr, consiste à '\n'.joinajouter au préalable le nom en conséquence:

n = "\n".join(names)
text = f"Winners are:\n{n}"

ce qui donne le même résultat.

Remarque:

C'est l'une des petites différences entre f-strings et str.format. Dans ce dernier, vous pouvez toujours utiliser la ponctuation à condition qu'un dict loufoque correspondant soit décompressé qui contient ces clés:

>>> "{\\} {*}".format(**{"\\": 'Hello', "*": 'World!'})
"Hello World!"

(Veuillez ne pas faire ça.)

Dans le premier cas, la ponctuation n'est pas autorisée car vous ne pouvez pas avoir d'identificateurs qui les utilisent.


À part: j'opterais certainement pour printou format, comme le suggèrent les autres réponses comme alternative. Les options que j'ai données ne s'appliquent que si vous devez pour une raison quelconque utiliser des chaînes f.

Ce n'est pas parce que quelque chose est nouveau que vous devriez essayer de tout faire avec ;-)

Dimitris Fasarakis Hilliard
la source
55

Vous n'avez pas besoin de chaînes f ou d'autres formateurs pour imprimer une liste de chaînes avec un séparateur. Utilisez simplement l' separgument mot - clé pour print():

names = ['Adam', 'Bob', 'Cyril']
print('Winners are:', *names, sep='\n')

Production:

Winners are:
Adam
Bob
Cyril

Cela dit, utiliser str.join()/str.format() here serait sans doute plus simple et plus lisible que toute solution de contournement de chaîne f:

print('\n'.join(['Winners are:', *names]))
print('Winners are:\n{}'.format('\n'.join(names)))
Eugène Yarmash
la source
13
Meilleure réponse à ce jour. J'utilise le déballage en étoile dans la fonction d'impression tout le temps ces jours-ci pour jeter un œil à l'intérieur d'un objet, par exemple print(*dir(some_object), sep='\n')ou print(*vars(some_object), sep='\n').
Rick soutient Monica le
1
Que faites-vous si vous ne souhaitez pas imprimer la liste directement, par exemple si vous la transmettez à un enregistreur?
bob le
1
@bob: alors utilisez simplement str.join(): text = '\n'.join(['Winners are:', *names]). BTW, print()peut être utilisé pour écrire dans n'importe quel fichier (spécifié avec l' fileargument, sys.stdoutpar défaut).
Eugene Yarmash le
10

Vous ne pouvez pas utiliser de barres obliques inverses dans les chaînes f comme d'autres l'ont dit, mais vous pouvez contourner cela en utilisant os.linesep(bien que notez que cela ne sera pas \nsur toutes les plates-formes et n'est pas recommandé à moins de lire / écrire des fichiers binaires; voir les commentaires de Rick ):

>>> import os
>>> names = ['Adam', 'Bob', 'Cyril']
>>> print(f"Winners are:\n{os.linesep.join(names)}")
Winners are:
Adam
Bob
Cyril 

Ou peut-être d'une manière moins lisible, mais garantie d'être \n, avec chr():

>>> print(f"Winners are:\n{chr(10).join(names)}")
Winners are:
Adam
Bob
Cyril
Chris_Rands
la source
2
Ce n'était pas moi, mais l'utilisation os.linesepn'est pas une bonne idée lors de la rédaction de texte.
Rick soutient Monica le
1
@RickTeachey J'ai déjà ajouté la mise en garde entre parenthèses et suggéré une approche alternative. Quoi qu'il en soit, l'OP imprime à l'écran,
n'écrit
Je ne pense pas que cela compte. os.linesepest juste pour la lecture, ou la lecture et l'écriture en mode binaire . Je sais que cela fonctionnera de la même manière dans ce cas, mais c'est une mauvaise habitude de commencer. Mais encore une fois: je n'étais pas le contre. La mise en garde me suffit. :)
Rick soutient Monica le
6

Les autres réponses donnent des idées sur la façon de mettre le caractère de nouvelle ligne dans un champ de chaîne f. Cependant, je dirais que pour l'exemple donné par l'OP (qui peut ou non être indicatif du cas d'utilisation réel de l'OP), aucune de ces idées ne devrait réellement être utilisée.

L'intérêt de l'utilisation de chaînes f est d'augmenter la lisibilité du code. Il n'y a rien que vous puissiez faire avec des chaînes f que vous ne pouvez pas faire format. Examinez attentivement s'il y a quelque chose de plus lisible à ce sujet (si vous pouviez le faire):

f"Winners are:\n{'\n'.join(names)}"

...ou ca:

newline = '\n'
f"Winners are:\n{newline.join(names)}"

...ou ca:

"Winners are:\n{chr(10).join(names)}"

vs ceci:

"Winners are:\n{}".format('\n'.join(names))

Le dernier moyen est au moins aussi lisible, sinon plus.

En bref: n'utilisez pas de marteau lorsque vous avez besoin d'un tournevis simplement parce que vous en avez un neuf brillant. Le code est lu beaucoup plus souvent qu'il n'est écrit.

Pour d'autres cas d'utilisation, oui, il est possible que l' chr(10)idée ou l' newlineidée soit appropriée. Mais pas pour celui donné.

Rick soutient Monica
la source
7
La lisibilité est subjective :) ... la vieille pratique convient aux personnes expérimentées et peut être plus lisible dans certains cas, mais peut être presque inconnue des noobs et donc illisible pour eux. Désolé pour le point de vue philosophique.
malmed
2
@malmed La lisibilité n'est généralement pas subjective. Certainement pas dans ce cas. Mais cela ne vaut pas la peine de discuter longuement.
Rick soutient Monica le
@malmed Vous avez raison de dire que la lisibilité est "subjective" en ce sens qu'elle peut être entraînée par l'expérience antérieure. Mais parce que notre cerveau et nos sens ont des limites, la lisibilité peut être mesurée objectivement en termes de facilité physique de scanner le texte pertinent, de fréquence à laquelle le cerveau humain a tendance à le faire correspondre correctement, à quel point il fait allusion à nos prédictions cérébrales sur d'autres code (y compris le début d'une déclaration / ligne indiquant ce que sera la fin), et avec quelle facilité il devient plus lisible pour un novice.
mtraceur le