Le formatage de chaînes consiste à convertir des valeurs en chaînes et à les insérer dans un gabarit de chaîne. Le Zen de Python affirme qu'il devrait y avoir « une seule façon évidente de faire quelque chose en Python ». Mais lorsqu'il s'agit de formatage de chaînes, les choses sont un peu... moins zen.
Il peut être surprenant de découvrir qu'il existe quatre façons principales de formater des chaînes en Python, chacune adaptée à un scénario différent.
Cela tient en partie à la longue histoire de Python, et en partie à des considérations comme l'internationalisation ou la validation des entrées.
On commencera par les ajouts les plus récents à la boîte à outils du formatage de chaînes, pour remonter ensuite jusqu'au formatage « à l'ancienne », ou de style printf().
f-string
Introduites dans Python 3.6, les f-strings (abréviation de « formatted strings ») ou l'interpolation littérale de chaînes, permettent d'évaluer (et de formater) rapidement et efficacement des expressions et des chaînes vers un type str, à l'aide du préfixe f (ou F) placé avant les guillemets (comme ceci : f'{object}').
Les f-strings fonctionnent avec tous les types de guillemets englobants, qu'il s'agisse de chaînes sur une seule ligne (' ou ") ou sur plusieurs lignes (''' ou """).
Toute variable, expression ou autre type placé à l'intérieur des {} est d'abord évalué, puis converti en str, et enfin concaténé avec les str situés à l'extérieur des accolades.
Dans cet exemple, on insère deux valeurs de variables dans une phrase (un str et un float) :
>>> name = 'eighth'
>>> value = 1/8
# The f-string, using the two values.
# The .2f format code truncates, so the value displays as 0.12.
>>> f'An {name} is approximately {value:.2f}.'
'An eighth is approximately 0.12.'
Les expressions évaluées peuvent être à peu près n'importe quoi.
Parmi le (vaste) éventail des possibilités : des str, des nombres, des variables, des expressions arithmétiques, des expressions conditionnelles, des types intégrés, des tranches, des fonctions, des lambdas, des compréhensions, ou n'importe quel objet doté d'une méthode __str__ ou __repr__.
Du plus simple au plus complexe :
Insérer une variable : l'utilisation la plus simple d'une f-string consiste à placer directement une variable dans la chaîne.
# Assigning a variable.
>>> name = "World"
# Inserting that variable.
>>> f'Hello, {name}!'
'Hello, World!'
Des expressions dans les {} : toute expression Python valide peut être évaluée à l'intérieur des accolades.
À noter que l'usage de guillemets doubles dans une f-string délimitée par des guillemets simples (ou l'inverse) évite d'avoir recours à des séquences d'échappement :
# A dictionary of key:value pairs.
>>> waves = {'water': 1, 'light': 3, 'sound': 5}
# Inserting the whole dict.
>>> f'Wave ranks: {waves}'
"Wave ranks: {'water': 1, 'light': 3, 'sound': 5}"
# An expression can be evaluated inline:
>>> f"Tenfold the value of 'light' is {waves['light'] * 10}."
"Tenfold the value of 'light' is 30."
# A method call can also be evaluated inline:
>>> f'{"hello world!".title()} is a classic greeting.'
'Hello World! is a classic greeting.'
# An f-string can be nested inside another f-string:
>>> f"{f'hello world!'.title()} is a classic greeting."
'Hello World! is a classic greeting.'
Le formatage de la sortie : le mini-langage de spécification de format permet de contrôler l'alignement, la précision numérique, et bien plus encore.
La spécification de format se place après la valeur, séparée par un :.
# Right-align a value to ten characters, and round it to 3 decimal places.
>>> value = 1 / 7
>>> f'One seventh is {value:10.3f}.'
'One seventh is 0.143.'
# A format specification can be set using variables as well.
>>> padding = 10
>>> precision = 3
>>> f'One seventh is {value:{padding}.{precision}f}.'
'One seventh is 0.143.'
Le tout ensemble : variables, expressions, appels de fonctions et formatage de la sortie :
>>> precision = 3
>>> f"{30e8 * 111_000:6.{precision}e}"
'3.330e+14'
>>> verb = 'meet'
>>> the_end = ['end', 'of', 'transmission']
>>> f'"Have a {"NICE".lower()} day, I will {verb} you after {30e8 * 111_000:6.{precision}e} light-years."{the_end}'
'"Have a nice day, I will meet you after 3.330e+14 light-years."[\'end\', \'of\', \'transmission\']'
# Did you notice the escaped single-quotes in the previous example?
# Using double quotes instead of single quotes for the f-string means the list's single-quoted strings print cleanly.
>>> f"Have a nice day. {the_end}"
"Have a nice day. ['end', 'of', 'transmission']"
Il y a deux limitations principales à connaître.
Les expressions des f-string ne peuvent pas être vides.
De plus, avant Python 3.12, elles ne pouvaient pas contenir de commentaires.
>>> f"An empty expression will error: {}"
SyntaxError: f-string: empty expression not allowed
>>> word = 'word'
>>> f"""A comment in a triple quoted f-string: {
word # I chose a nice variable
}"""
'A comment in a triple quoted f-string: word'
L'interpolation de chaînes ne peut pas être utilisée avec l'API GNU gettext pour l'internationalisation (I18N) et la localisation (L10N). Il est donc recommandé d'utiliser la classe string.Template ou la méthode str.format() présentées plus bas, plutôt qu'une f-string, dans tous les scénarios de traduction qui consistent à encapsuler des strings.
Garde aussi à l'esprit que l'utilisation d'expressions à l'intérieur des accolades {} d'une f-string s'apparente à l'usage de eval() ou exec() : ce n'est donc pas très sûr et cela ne doit jamais être utilisé avec des entrées fournies par l'utilisateur.
str.format()
La méthode str.format() remplace les espaces réservés d'une chaîne par les valeurs passées en arguments à la fonction.
Les espaces réservés sont identifiés par des noms ({price}), des nombres ({0} ou des indices), ou même des espaces réservés vides (positionnels) {}.
Par exemple :
# A named placeholder and a positional placeholder.
>>> 'My text: {placeholder_1} and {}.'.format(12, placeholder_1='named placeholder')
'My text: named placeholder and 12.'
Comme les f-strings, str.format() de Python prend en charge tout un éventail de spécificateurs de format du mini-langage, qui permettent d'aligner du texte, de tronquer des flottants, et bien plus encore.
Le motif complet d'un spécificateur de format est {[<name>][!<conversion>][:<format_specifier>]} :
<name> peut être un espace réservé nommé, un nombre, ou vide.!<conversion> est facultatif et doit être l'une de ces trois conversions : !s pour str(), !r pour repr() ou !a pour ascii().
Par défaut, c'est str() qui est utilisée.:<format_specifier> est facultatif et contrôle la façon dont la valeur est affichée.
Plus d'informations sur les options possibles sont disponibles ici.Exemple de conversions pour une lettre diacritique :
# Fills in the object at index zero, converted to a string.
>>> 'An e with an umlaut: {0!s}'.format('ë')
'An e with an umlaut: ë'
# Fills in the object at index zero, converted to a repr.
>>> 'An e with an umlaut (object representation): {0!r}'.format('ë')
"An e with an umlaut (object representation): 'ë'"
# Fills in the object at index zero, converted to ASCII.
>>> 'An e with an umlaut converted into ASCII: {0!a}'.format('ë')
"An e with an umlaut converted into ASCII: '\xeb'"
# Fills in the object in the first position,
# then fills in the object in the second position formatted as a repr.
>>> 'She said her name is not {} but {!r}.'.format('Chloe', 'Zoë')
"She said her name is not Chloe but 'Zoë'."
Exemples de spécificateurs de format courants :
# Integer and binary/hex representations of the same number.
>>> my_num = 42
>>> f"{my_num} in binary is {my_num:b}. In hex, it is {my_num:x}"
"42 in binary is 101010. In hex, it is 2a"
# Alignment: left (<), right (>), and center (^) using up to ten characters total.
>>> f"[{"left":<10}] [{"right":>10}] [{"center":^10}]"
"[left ] [ right] [ center ]"
# Float precision and scientific notation (up to three decimal places).
>>> pi = 3.141592653589793
>>> f"Fixed: {pi:.3} Scientific: {pi:.3e}"
"Fixed: 3.142 Scientific: 3.142e+00"
# Thousands separator and percentage.
>>> balance = 1000
>>> rate = 0.0225
>>> f"Balance: ${balance:,.0f} Interest rate: {rate:.1%}"
"Balance: $1,000 Interest rate: 2.2%"
# Putting it all together:
>>> items = [("Widget", 1250, 9.991), ("Gadget", 37, 24.503), ("Doohickey", 4, 149.002)]
>>> header = f"{"Item":<12} {"Qty":>6} {"Price":>9}"
>>> print(header)
Item Qty Price
>>> for name, qty, price in items:
... print(f"{name:<12} {qty:>6} {price:>9.2f}")
Widget 1250 9.99
Gadget 37 24.50
Doohickey 4 149.00
D'autres exemples figurent à la fin de cette documentation.
%, ou de style printf()
L'utilisation de l'opérateur % pour le formatage est la plus ancienne méthode de formatage de chaînes en Python.
Elle vient du langage C et permet d'utiliser des arguments positionnels pour construire un str.
Cette méthode a été supplantée à la fois par les f-strings et par str.format(), d'où son surnom de « Old Style ».
On la rencontre encore dans du code Python 2 et/ou hérité.
Bien qu'elle fonctionne toujours en Python 3.x, le formatage avec % est généralement évité, car il est source d'erreurs, moins efficace, propose moins d'options, et le moindre décalage entre un espace réservé et son argument peut lever une exception.
L'usage de l'opérateur % s'apparente à printf(), aussi l'appelle-t-on parfois le formatage à la printf.
# Assigning a variable.
>>> name = "Anna-conda"
# Building a string using %.
>>> "The snake's name is %s." % name
"The snake's name is Anna-conda."
Dans l'exemple ci-dessus, l'opérateur % remplace l'espace réservé %s par la variable name à l'exécution.
Pour ajouter plusieurs variables à une chaîne, il faut fournir un tuple contenant un objet par espace réservé, après le % :
# Assigning variables.
>>> name = "Billy the Kid"
>>> fruit = "grapes"
# Building a string using %.
>>> "Surprisingly, %s's favorite snack was %s." %(name, fruit)
"Surprisingly, Billy the Kid's favorite snack was grapes."
string.Template() (à ne pas confondre avec les t-strings de Python 3.14) est une classe du module string (par opposition au type str intégré), qui fait partie de la bibliothèque standard de Python, mais doit être importée pour être utilisée.
Les template strings prennent en charge la substitution à base de $ et sont bien plus simples et moins puissantes que les autres options mentionnées ici.
Elles peuvent toutefois être très utiles pour une internationalisation compliquée ou pour assainir des entrées externes.
string.Template est considérée comme plus sûre face à des entrées utilisateur non fiables, car elle empêche d'évaluer des expressions arbitraires ou d'accéder aux attributs des objets, ce qui atténue les attaques par injection de chaînes de format.
>>> from string import Template
>>> name = "Anna-Conda"
# Creating a Template with placeholder text.
>>> template_string = Template("The snake called `$snake_name` has escaped!")
# Calling .substitute() to replace the placeholder with a value.
>>> template_string.substitute(snake_name=name)
'The snake called `Anna-Conda` has escaped!'
Plus d'informations sur string.Template sont disponibles dans la documentation de Python.
Avec toutes ces options et tous ces mini-langages, comment décider quoi utiliser pour formater des chaînes en Python ? Voici quelques conseils rapides :
Les f-strings sont les plus récentes et les plus faciles à lire.
Si tu n'as pas besoin d'internationaliser, c'est la méthode à privilégier à partir de Python 3.6.
str.format() est polyvalente, puissante et compatible à la fois avec gnu gettext et avec la plupart des versions de Python.
Si ce dont tu as besoin, c'est de simplicité, de sécurité et/ou d'une internationalisation poussée, tu peux utiliser string.Template() pour atténuer les risques lorsqu'il faut traiter des entrées provenant d'utilisateurs, et pour encapsuler des strings de traduction.
L'opérateur % est généralement considéré comme obsolète pour du code nouveau, même s'il fonctionne encore en Python moderne.
Il ne devrait servir la plupart du temps qu'à assurer la compatibilité avec d'anciennes bases de code.
Le formatage avec % est plus source d'erreurs (et offre moins de fonctionnalités) que les autres méthodes, et il peut poser des problèmes d'affichage des caractères non ASCII.
Si tu comptes l'utiliser, vérifie les détails de prise en charge de ta distribution Python spécifique.
Si tu veux aller plus loin, tout sur le formatage et Python String Formatting Best Practices sont de bons points de départ.