Le formatage des chaînes de caractères avec Python

Il existe plusieurs façons de faire de la concaténation dans une chaîne de caractères. Depuis la version 3.6 de Python, une des façons de faire les plus efficaces est d'utiliser les f-string.

Publié le par Thibault Houdon (mis à jour le )
paceTemps de lecture estimé : 45 minutes

Le terme de « formatage » de chaînes n'a rien à voir avec le formatage d'un disque dur.

Par « formatage », on entend « mise en forme » et il existe de nombreuses façons de mettre en forme des chaînes de caractères avec Python.

Dans cet article, nous allons donc passer en revue différentes façons de « formater » des chaînes de caractères.

Au commencement, il y avait la concaténation

Avant de parler de formatage, on parle souvent de concaténation.

La concaténation consiste à mettre bout à bout plusieurs chaînes de caractères.

La concaténation peut se faire très simplement avec l'opérateur mathématique + :

protocole = "https://"
nom_du_site = "Docstring"
extension = "fr"

url = protocole + "www." + nom_du_site + "." + extension

Ça fonctionne, mais très rapidement vous allez observer deux problèmes :

  • Ce n'est pas très agréable à lire.
  • Vous ne pouvez concaténer que des objets du même type (car Python est un langage fortement typé).

Ainsi, le code suivant retournera une erreur car la variable age est un nombre entier :

>>> age = 26
>>> phrase = "J'ai " + age + " ans."
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: must be str, not int

Pour palier à cette erreur, il faut convertir la variable age en chaîne de caractères :

>>> age = 26
>>> phrase = "J'ai " + str(age) + " ans."
"J'ai 26 ans."

Et on retombe sur le premier problème : ça devient très vite difficile à lire et c'est le meilleur moyen de se retrouver avec des TypeError.

Il existe un autre moyen d'insérer des objets dans une chaîne de caractères qui permet de spécifier directement le type des données insérées.

Cette façon de faire est obsolète mais on continue de la retrouver dans de nombreux scripts Python. Il est important de comprendre donc de quoi il en retourne.

Pour ce faire, on utilise l'opérateur modulo (%) et on spécifie ensuite le format des données que l'on insère dans la chaîne de caractères.

age = 26
phrase = "J'ai %d ans." %age  # "J'ai 26 ans."
phrase = "J'ai %f ans." %age  # "J'ai 26.000000 ans."
  • En utilisant %d on se retrouve avec un nombre entier.
  • En utilisant %f, la variable age, qui est au départ un nombre entier, se retrouve dans la chaîne de caractères sous forme de nombre décimal.

Cette façon de faire a été longtemps la méthode privilégiée pour formater des chaînes de caractères, raison pour laquelle vous la verrez souvent dans certains scripts.

Certains continuent même d'utiliser cette façon de faire alors qu'il existe maintenant des méthodes bien plus efficaces comme celles que nous allons voir dans la suite de cet article.

La méthode format

Pour éviter les erreurs de type et insérer des objets dans une chaîne de caractères, on peut utiliser la méthode format.

Cette méthode permet d'insérer des objets à l'intérieur d'emplacements spécifiés dans la chaîne de caractères par des accolades :

age = 26
phrase = "J'ai {} ans".format(age)

Ici, pas besoin de convertir la variable age en chaîne de caractères. La méthode format s'en charge pour nous et nous évitons ainsi le TypeError.

Cela permet également de garder une certaine continuité dans notre chaîne de caractères qui ne se retrouve pas entrecoupée d'opérateurs +.

On peut également spécifier à l'intérieur des accolades un nom qu'on utilisera comme paramètre dans la méthode format pour obtenir une phrase encore plus claire :

age_de_lutilisateur = 26
phrase = "J'ai {age} ans".format(age=age_de_lutilisateur)

On peut mettre autant d'emplacements dans une chaîne de caractères que nécessaire.

Il faudra cependant faire attention de passer autant d'éléments à la méthode format qu'il y a d'emplacements dans notre chaîne de caractères.

Par exemple, le code suivant fonctionne :

prenom = "Pierre"
age = 26
phrase = "Je m'appelle {} et j'ai {} ans.".format(prenom, age)

Mais le code ci-dessous retournera une erreur (IndexError: tuple index out of range) car il y a deux emplacements dans la chaîne de caractères mais un seul élément est passé à la méthode format :

prenom = "Pierre"
age = 26
phrase = "Je m'appelle {} et j'ai {} ans.".format(prenom)

On peut également spécifier à l'intérieur des accolades un indice, qui fera référence à la position de l'argument de la méthode format à utiliser.

C'est très pratique si vous souhaitez réutiliser un argument :

prenom = "Pierre"
age = 26
langage = "Python"
phrase = "Je m'appelle {0} et j'ai {1} ans. {0} apprends le langage {2}.".format(prenom, age, langage)
# Je m'appelle Pierre et j'ai 26 ans. Pierre apprends le langage Python.

On peut également remettre des noms à l'intérieur des accolades afin d'obtenir quelque chose de plus agréable à lire :

prenom = "Pierre"
age = 26
langage = "Python"
phrase = "Je m'appelle {prenom} et j'ai {age} ans. {prenom} apprends le langage {langage}.".format(prenom=prenom, age=age, langage=langage)

Le nom que vous mettez à l'intérieur des accolades n'a pas besoin d'être le même que la variable que vous passez à la méthode format. On aurait très bien pu faire :

prenom = "Pierre"
age = 26
langage = "Python"
phrase = "Je m'appelle {user} et j'ai {age} ans. {user} apprends le langage {learning}.".format(user=prenom, age=age, learning=langage)

La méthode format permet donc d'obtenir un code beaucoup plus facile à lire et évite de s'embêter avec les fonctions de conversion.

Si on reprend l'exemple de l'URL du début de l'article :

protocole = "https://"
nom_du_site = "Docstring"
extension = "fr"

# Avec l'opérateur +
url = protocole + "www." + nom_du_site + "." + extension

# Avec la méthode format
url = "{}www.{}.{}".format(protocole, nom_du_site, extension)
url = "{protocole}www.{domaine}.{extension}".format(protocole=protocole, domaine=nom_du_site, extension="fr")

Les f-string

Depuis la version 3.6 de Python, une fonctionnalité très intéressante a fait son apparition : les f-string.

Derrière ce nom un peu bizarre se trouve une façon très efficace de formater des chaînes de caractères.

C'est vrai autant pour la lisibilité que pour les performances, qui seront meilleures qu'avec la méthode format (ça reste de l'ordre du millième de milliseconde mais tout de même).

Pour utiliser les f-string, il suffit de rajouter la lettre f devant votre chaîne de caractères :

phrase = f"Je suis un f-string."

On peut ensuite, comme avec la méthode format, insérer des données dans la chaîne de caractères avec les accolades.

La différence majeure réside dans le fait qu'on peut écrire du code Python directement dans les accolades.

On retrouve donc la flexibilité de la méthode format mais avec quelque chose d'encore plus facile à lire.

Reprenons l'exemple de l'URL :

protocole = "https://"
nom_du_site = "Docstring"
extension = "fr"

url = f"{protocole}www.{nom_du_site}.{extension}"  # https://www.Docstring.fr

Vous souhaitez mettre le nom du site en minuscule ?

Aucun problème, on peut utiliser la méthode lower directement à l'intérieur du f-string :

protocole = "https://"
nom_du_site = "Docstring"
extension = "fr"

url = f"{protocole}www.{nom_du_site.lower()}.{extension}"
# https://www.docstring.fr

On peut insérer n'importe quel type d'objet dans un f-string sans que cela ne pose de problème à Python :

liste = ['Pommes', 'Poires', 'Bananes']
print(f"Voici votre liste de courses : {liste}")
# Voici votre liste de courses : ['Pommes', 'Poires', 'Bananes']

Et comme toujours, on peut écrire du code Python directement à l'intérieur des accolades :

liste = ['Pommes', 'Poires', 'Bananes']
print(f"Voici votre liste de courses : {', '.join(liste)}")
Voici votre liste de courses : Pommes, Poires, Bananes

Faites attention cependant à garder un code facile à lire ! Ce n'est pas parce qu'on peut tout faire à l'intérieur d'un f-string qu'on doit le faire !

Par exemple, évitez de faire ceci :

liste = ['Pommes', 'Poires', 'Bananes']
print(f"Voici votre liste de courses : {', '.join([fruit.upper() if fruit.lower() == 'pommes' else fruit for fruit in liste])}")
# Voici votre liste de courses : POMMES, Poires, Bananes

Il vaut mieux découper un peu plus notre code pour le rendre plus lisible :

liste = ['Pommes', 'Poires', 'Bananes']
liste_final = [fruit.upper() if fruit.lower() == 'pommes' else fruit for fruit in liste]
liste_format = ', '.join(liste_final)
print(f"Voici votre liste de courses : {liste_format}")
# Voici votre liste de courses : POMMES, Poires, Bananes

Et si après ça vous oubliez d'acheter des pommes, je ne peux plus rien pour vous 🤷‍♂️

Pour finir, sachez qu'il est tout à fait possible de créer un f-string sur plusieurs lignes :

prenom = "Pierre"
phrase = (
  f"Bonjour {prenom} et "
  "bienvenue sur Docstring. "
  f"Passez une bonne journée {prenom} !"
)
# 'Bonjour Pierre et bienvenue sur Docstring. Passez une bonne journée Pierre !'

Les caractères spéciaux

Vous l'avez peut-être vu venir...

On utilise des accolades pour indiquer des emplacements à l'intérieur d'une chaîne de caractères.

Comment faire alors pour insérer des accolades 🤯 ?

👉 Facile, il suffit de les tripler !

>>> prenom = "Pierre"
>>> f"Je me nomme {{prenom}}"
'Je me nomme {prenom}'
>>> f"Je me nomme {{{prenom}}}"
'Je me nomme {Pierre}'

Si vous doublez les accolades, la variable ne sera pas évaluée (les accolades sont bien visibles mais on retrouve la chaîne de caractères prenom au lieu de sa valeur).

En triplant les accolades, on a bien des accolades qui entourent la valeur associée à la variable prenom.

👉 Faites attention également de varier les guillemets si vous utilisez du code Python à l'intérieur d'un f-string !

Par exemple, pour récupérer la clé d'un dictionnaire :

profession = {'Pierre': 'ingénieur'}
phrase = f"Pierre est {profession["Pierre"]}"
# SyntaxError: invalid syntax

Les guillemets ferment la chaîne de caractères et on se retrouve avec une erreur de syntaxe.

Il faut donc utiliser des guillemets simple (ou vice-versa) :

profession = {'Pierre': 'ingénieur'}
phrase = f"Pierre est {profession['Pierre']}"
phrase = f'Pierre est {profession["Pierre"]}'

Quelques options de formatage

Il est possible de spécifier des options de formatage avancées directement à l'intérieur des accolades.

Les options de formatages sont séparées des données par le symbole des deux-points :

f"{valeur:formatage}"

Les options suivantes sont disponibles à la fois avec les f-string et la méthode format.

Voici une liste non exhaustive d'options de formatage que j'utilise très souvent.

'Padder' un nombre

Vous pouvez rajouter des 0 avant le nombre indiqué (ici 12) pour remplir la chaîne de caractères jusqu'à atteindre le nombre de caractères indiqués (ici 4) :

f"{12:04d}"  # '0012'

Ici, Python va donc rajouter 2 zéros par la gauche pour arriver à un total de 4 caractères (0012).

Très pratique quand vous travaillez avec des séquences.

for i in range(100):
    image_path = f"image_{i:04d}.jpg" # image_0001.jpg

Formater une date

J'utilise cette astuce sur cet article pour afficher la date en haut de cette page 😉

Pour une liste plus complète des options de formatage disponibles pour les objets de type date, je vous conseille ce site très bien fait.

from datetime import datetime
f'{datetime(2020, 8, 7, 9, 0):Le %Y-%m-%d à %H:%M}'
# 'Le 2020-08-07 à 09:00'

Tronquer une chaîne de caractères

Utile pour tous les endroits où vous avez un nombre limité de caractères (les descriptions de vidéos YouTube, articles de blogs etc).

phrase = """Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
            Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
            Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."""

description = f"{phrase:.60}"
# 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed'

Il existe d'autres façons plus efficaces de tronquer une chaîne de caractères, notamment la fonction textwrap.shorten de la librairie standard qui permet en plus d'ajouter facilement des points de suspension à la fin de la phrase.

L'avantage de format sur les f-string

La plupart du temps, les f-string sont beaucoup plus agréables à lire et facile à utiliser que la méthode format.

J'utilise 95% du temps les f-string mais il reste encore quelques cas de figure dans lesquels la méthode format est utile.

Le principal avantage de la méthode format est que vous pouvez définir votre chaîne de caractères à un endroit de votre script et ne l'utiliser que plus tard.

Les f-string nécessitent que les variables que vous insérez dans votre chaîne de caractères soient disponibles immédiatement.

Si vous essayez d'insérer dans un f-string une variable qui n'a pas encore été déclarée, vous obtiendrez évidemment une erreur :

>>> prenom = "Pierre"
>>> phrase = f"Bonjour {prenom}, cette semaine vous avez regardé {nombre} vidéos."
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'nombre' is not defined

Or, il arrive que l'on définisse des chaînes de caractères à utiliser dans un fichier de configuration et que l'on souhaite utiliser ces phrases à différents endroits de notre script avec des variables qui seront définies par la suite.

# constants.py
BONJOUR = "Bienvenue {prenom}, vous avez regardé {nombre_videos} vidéos cette semaine."
AU_REVOIR = "À bientôt {prenom} !"
# main.py
from constants import BONJOUR

user = input("Entrez votre nom d'utilisateur : ")
progression = get_weekly_progress(user)

message_de_bienvenue = BONJOUR.format(prenom=user, nombre_videos=progression)
print(message_de_bienvenue)

Ici, on définit des phrases à afficher dans un fichier constants.py.

On utilise ensuite ces phrases en les formatant dans le script main.py.

On pourrait ainsi ré-utiliser ces phrases dans plusieurs scripts sans avoir besoin de les réécrire à chaque fois.

Comment savoir quelle méthode utiliser ?

Comme souvent, ça dépend. Il y a déjà souvent la préférence personnelle qui joue.

Personnellement j'aime beaucoup les f-string et je les utilise dès que possible.

Il se peut cependant que vous soyez obligés par le projet sur lequel vous travaillez d'utiliser la méthode format pour des raisons de rétrocompatibilité.

Les f-string n'ayant été introduits que dans la version 3.6 de Python, si votre code doit fonctionner sur la version 2 et la version 3 de Python, vous serez obligé d'utiliser la méthode format.

La méthode de formatage avec le symbole % est à proscrire, elle est désormais obsolète depuis plusieurs années.

La méthode format reste encore à privilégier dans certains cas de figure comme ceux que nous avons vu ci-dessus.

Pour tout le reste, les f-string sont vos amis 🤗