Chaînes formatées classiques¶
L’essentiel¶
Les chaînes formatées classiques¶
La méthode historique de formatage de chaînes en Python (qualifiée de méthode « classique » dans ce document) héritée du C et disponible en Java, reste utilisable mais la méthode format
lui est explicitement préférée dans la documentation officielle. En outre, depuis l’apparition des f-chaînes, la méthode classique présente moins d’avantages en concision ou lisibilité.
Présentons justement la méthode classique. Soient les chaînes formatées suivantes :
Son nom est titi et il a 8 ans.
Son nom est Arthur et il a 30 ans.
Son nom est Alfred et il a 100 ans.
Voici le code Python permettant de produire les chaînes formatées ci-dessus :
1 2 3 4 5 6 7 8 9 | modele = "Son nom est %s et il a %s ans."
a = modele %("titi", 8)
print(a)
b = modele %("Arthur", 30)
print(b)
print("Son nom est %s et il a %s ans." %("Alfred", 100))
|
10 11 12 | Son nom est titi et il a 8 ans.
Son nom est Arthur et il a 30 ans.
Son nom est Alfred et il a 100 ans.
|
- Ligne 1 : le gabarit. C’est une chaîne Python. Les zones à remplacer sont marquées dans le gabarit par
%s
; dans l’exemple, il y a deux zones de remplacement dans le gabarit. - Ligne 3 : construction de la chaîne formatée (qui est affichée ligne 10). La syntaxe
%("titi", 8)
indique ce par quoi les zones de la forme%s
vont être remplacées dans le gabarit. Le premier « %s » dans le gabarit est remplacé par le premier élément après la parenthèse. De même pour le deuxième%s
. - Lignes 9 et 12 : noter que l’on n’est pas obligé de placer la gabarit dans une variable.
Description d’une chaîne formatée¶
On va décrire la syntaxe d’une chaîne formatée en se basant sur l’exemple suivant :
1 2 | s = "Son nom est %s et il a %s ans." %("Alfred", 100)
print(s)
|
3 | Son nom est Alfred et il a 100 ans.
|
L’expression complète
"Son nom est %s et il a %s ans." %("Alfred", 100)
est une chaîne formatée.
Elle se décompose en trois parties, de gauche à droite :
- le format
- l’opérateur
%
- le tuple de remplacement
Le format¶
Le format se présente comme une simple chaîne Python. Dans l’exemple, il s’agit de la chaîne littérale
1 | "Je m'appelle %s et j'ai %s ans"
|
Chaque valeur à remplacer dans cette chaîne (dans l’exemple le nom et l’âge) est signalée par le symbole %
suivi d’une lettre particulière (ici s
).
Le format représente un modèle (un gabarit) dans lequel seront effectuées des substitutions.
L’opérateur %
¶
L’opérateur %
se place après le format et avant l’objet contenant les valeurs de remplacement.
Cet opérateur est l’opérateur modulo de division entière mais dans ce contexte on l’appelle plutôt l’opérateur de formatage de chaîne, parfois aussi connu sous le nom d’opérateur d”interpolation de chaîne.
L’opérateur de formatage %
est un opérateur comme un autre, au même titre que +
ou *
. Il peut être entouré d’autant d’espaces avant et après :
1 2 | s = "Son nom est %s et il a %s ans." % ("Alfred", 100)
print(s)
|
3 | Son nom est Alfred et il a 100 ans.
|
- Ligne 1: on a placé des espaces avant et après l’opérateur
%
Double usage du symbole %
¶
On notera donc que le symbole %
s’utilise dans des contextes différents :
- dans le format pour marquer le début des emplacements à remplacer ;
- dans la chaîne formatée pour signaler l’objet contenant les valeurs de remplacement correspondantes.
Dans le format, %
est juste un marqueur interne et dans le deuxième cas, %
est un opérateur du langage Python.
Spécificateur de formatage¶
Les endroits de remplacement dans le format sont signalés par le symbole %
suivi d’un ou plusieurs caractères précisant comment le remplacement doit être fait.
Dans l’exemple ci-dessus, il s’agissait de %s
. Ces groupes placés dans le format et commençant par le symbole %
sont appelés des spécificateurs de formatage. Ils peuvent être plus complexes que ceux de l’exemple, comme %(toto) 010.2f
.
Type de conversion¶
Un spécificateur de formatage commence par %
et se termine par une lettre appelée le type de conversion.
La lettre indique quelle conversion la valeur de remplacement doit subir avant le remplacement. Par exemple, la lettre s
fait référence au type string (chaîne), la lettre f
fait référence au type float (flottant).
Dans l’exemple
1 | s = "Son nom est %s et il a %s ans." %("Alfred", 100)
|
le deuxième spécificateur %s
dans le format précise que la valeur de remplacement, ici 100, doit être convertie en une chaîne, plus précisément, la chaîne qui représente l’entier 100 en base 10.
Pour un autre type de conversion, le formatage aurait pu être différent. Par exemple, au lieu du type s
, on peut utiliser un type f
qui convertit la valeur en flottant :
1 2 | s = "Son nom est %s et il a %f ans" %("Alfred", 100)
print(s)
|
3 | Son nom est Alfred et il a 100.000000 ans
|
- L’entier 100 est converti en flottant avant remplacement
- Le remplacement se fait suivant un formatage flottant (séparateur décimal et 6 chiffres derrière).
Le formatage en string (avec s
donc) convient à beaucoup d’utilisations usuelles.
Valeurs de remplacement¶
Dans l’exemple, les valeurs de remplacement sont au nombre de deux : la chaîne Alfred et l’entier 100. Les valeurs de remplacement apparaissent séparées par des virgules et entourées de parenthèses. La paire de parenthèses représente en fait un tuple. Le tuple qui suit l’opérateur %
doit contenir autant de valeurs qu’il y a de spécificateurs de formatage présents dans le format.
Les valeurs de remplacement doivent figurer dans un tuple et pas dans une liste.
Tuple de remplacement¶
Soit le code suivant :
1 2 3 4 | gabarit = "Son nom est %s et il a %s ans."
a = gabarit %("titi", 8)
print(a)
|
5 | Son nom est titi et il a 8 ans.
|
Les valeurs de remplacement dans le gabarit apparaissent après l’opérateur %
et sont placées dans un tuple. Ainsi le code peut-être récrit :
1 2 3 4 | gabarit = "Son nom est %s et il a %s ans."
t = ("titi", 8)
a = gabarit %t
print(a)
|
Il est toutefois rare que l’on procède ainsi en pratique.
Cas d’une unique valeur de remplacement¶
Lorsqu’il y a une seule valeur à remplacer, la syntaxe d’une chaîne formatée peut être simplifiée en ignorant la notation de tuple pour le remplacement :
1 2 3 4 5 6 7 8 | print("Son nom est %s !!!" %"toto")
x = "titi"
print("Son nom est %s !!!" %x)
gabarit = "Son nom est %s !!!"
x = "titi"
print(gabarit %x)
|
9 10 11 | Son nom est toto !!!
Son nom est titi !!!
Son nom est titi !!!
|
- 3 variantes de la même syntaxe sont présentées ; dans chaque cas, un seul remplacement est fait et donc l’opérateur
%
n’est pas suivi d’une parenthèse.
Priorité de l’opérateur de remplacement¶
Observons le code suivant au comportement inattendu :
1 2 | print("Toto a %s ans" %20)
print("Toto a %s ans" %10*2)
|
3 4 | Toto a 20 ans
Toto a 10 ansToto a 10 ans
|
- Ligne 1:
%s
a été remplacé par 10 - Ligne 2 : bien que
10 * 2
vaille 20,%s
n’a pas été remplacé par 20.
Lorsque la valeur de remplacement fait l’objet d’une opération (ici une multiplication), il peut y avoir un conflit de priorité ou d’association avec l’opérateur %
de formatage.
Dans l’exemple ci-dessus, le comportement inattendu est en fait équivalent à :
1 2 | s = "Toto a %s ans" %10
print(s*2)
|
3 | Toto a 10 ansToto a 10 ans
|
Par précaution dans ce type de situation, on entourera de parenthèses la valeur à remplacer :
1 | print("Toto a %s ans" %(10*2))
|
2 | Toto a 20 ans
|
Priorité de %
¶
La priorité de l’opérateur %
de formatatge de chaîne est la même que celle de l’opérateur arithmétique %
.
Les opérateurs %
et *
ayant même priorité et la syntaxe du langage Python prévoyant que ces opérateurs s’associent de la gauche vers la droite, il en résulte que la chaîne formatée mon_format % v * 2
s’interprète (mon_format % v) * 2
.
En fonction des situations, on placera ou non des parenthèses pour changer les priorités. Voici quelques exemples :
1 2 3 4 5 6 7 8 | t = ("mardi", 19)
u = ("janvier", 2038)
z = "%s %s %s %s"%(t+u)
print(z)
z = "%s %s "%t + "%s %s"%u
print(z)
|
9 10 | mardi 19 janvier 2038
mardi 19 janvier 2038
|
Autre exemple :
1 2 3 4 5 | x = 10
y = 42
z= "température : %s" %-max(x, y)
print(z)
|
6 | température : -42
|
Options de formatage¶
Un formatage avec une chaîne formatée peut être affiné à l’aide de nombreuses options. Ces options sont plus ou moins utiles et plus ou moins complexes.
Pour les plus importantes, elles permettent, par exemple, de
- placer la valeur à formater dans un « champ » avec des espaces blancs à gauche ou à droite de la valeur,
- placer des zéros avant un nombre entier ou décimal,
- pour un nombre flottant, contrôler le nombre de décimales à placer dans la chaîne de remplacement
Dans le but de montrer la syntaxe des options, voici un exemple artificiellement complexe de chaîne formatée avec des options :
1 2 3 | dico = {"nom":"Alfred", "age": 100}
s = "Son nom est %(nom)s et il a %(age)0 8.3f ans" %dico
print(s)
|
4 | Son nom est Alfred et il a 100.000 ans
|
Les options de formatage se lisent (dans l’exemple, ligne 2) dans les spécificateurs de formatage entre le signe %
et la dernière lettre du spécificateur (et qui désigne le type de conversion). Dans l’exemple, le spécificateur de formatage %(age)0 8.3f
contient un certain nombre d’options (5 très précisément), que l’on peut extraire de la suite (age)0 8.3
Les spécificateurs %s
, %d
, %f
¶
Le caractère de conversion dans un spécificateur (comme s, d ou f) indique comment la valeur de remplacement va être interprétée. Les caractères de conversion les plus courants sont :
d
: la valeur est interprétée comme un entier sous forme décimale (d
comme decimal)s
: la valeur est interprétée comme une chaîne de caractères (s
comme string)f
: la valeur est interprétée comme un nombre décimal à virgule (f
comme float)
Voici quelques exemples :
1 2 | x = 3.1415926
print("pi vaut %f environ" %x)
|
3 | pi vaut 3.141593 environ
|
x
est est un flottant qui doit être interprété comme un flottant, d’où l’affichage
1 2 | x = 3.1415926
print("pi vaut %d environ" %x)
|
3 | pi vaut 3 environ
|
x
est un flottant mais il va être interprété comme un entier d’où l’affichage 3 (nombre entier, la partie décimale est supprimée).
Formatage d’un flottant avec %f
¶
On cherche à générer le format suivant
1 euro = XXXX dollar
où XXXX est le cours du dollar, par exemple
1 euro = 1,3142 dollar
1 euro = 1,53 dollar
1 euro = 1,279 dollar
XXXX représente donc un nombre flottant.
La syntaxe Python propose le spécificateur %f pour représenter dans une chaîne formatée les nombres décimaux à virgule :
1 2 3 | gabarit = "1 euro = %f dollar"
s = gabarit %1.3142
print(s)
|
4 | 1 euro = 1.314200 dollar
|
Ici, le f dans %f fait référence à flottant.
On observe (ligne 4) que le formatage de la valeur est différent de celui de la valeur entrée. La raison est que la précision par défaut du formatage est de 6 décimales.
Problème d’arrondi¶
Sans option particulière, le spécificateur %f
formate en 6 décimales par défaut ce qui affiche parfois un arrondi :
1 2 | x = 0.0000009563
print("%f" %x)
|
3 | 0.000001
|
Formatage d’un nombre avec %s
¶
Le spécificateur %s
convertit un nombre x
en une suite de caractères représentant x
en base 10.
Le cas des entiers¶
Pour les entiers, %s
et %d
sont équivalents :
1 2 3 4 5 | fs = "Mardi %s janvier %s" %(19, 2038)
fd = "Mardi %d janvier %d" %(19, 2038)
print(fs)
print(fd)
print(fs == fd)
|
6 7 8 | Mardi 19 janvier 2038
Mardi 19 janvier 2038
True
|
Le cas des flottants¶
Pour les flottants, %s
et %f
sont proches mais différent pour des raisons d’ajout de zéros :
1 2 3 4 5 | fs = "1 euro = %s dollar" %1.3142
ff = "1 euro = %f dollar" %1.3142
print(fs)
print(ff)
|
6 7 | 1 euro = 1.3142 dollar
1 euro = 1.314200 dollar
|
- Dans le cas de
%f
, les décimales ont été complétées par des zéros.
Comme le format %f
est limité, par défaut, à 6 décimales visibles, les représentations formatées par %s
et %f
peuvent différer :
1 2 3 4 | x = 0.1234678
print("%f" %x)
print("%s" %x)
|
5 6 | 0.123468
0.1234678
|
Précision d’affichage d’un flottant¶
Un nombre décimal peut être formaté avec un nombre de décimales que l’on peut choisir :
1 2 | x = 22/7
print("pi = %.2f" % x)
|
3 | pi = 3.14
|
Pour cela, on place un point après le signe %
et on indique la précision souhaitée (ci-dessus 2), c’est-à-dire le nombre de décimales.
La valeur remplacée est un arrondi de la valeur réelle et non pas une troncature :
1 2 3 | x = 3.1415926
print("pi = %.2f" % x)
print("pi = %.4f" % x)
|
4 5 | pi = 3.14
pi = 3.1416
|
Symbole %
dans une chaîne formatée¶
Supposons que l’on veuille générer des chaînes formatées du type
Inflation : XXXXX% par an
où XXXXX est un entier, par exemple :
1 2 3 | Inflation : 10% par an
Inflation : 3% par an
Inflation : 8% par an
|
La présence du symbole %
pose un problème de formatage puisque %
est à la fois un signe de remplacement et le caractère littéral de pourcentage :
1 2 | p = 10
print("Inflation : %d% par an" %p)
|
3 4 5 6 | Traceback (most recent call last):
File "_.py", line 2, in <module>
print("Inflation : %d% par an" %p)
TypeError: not enough arguments for format string
|
- Le deuxième
%
dans le format est interprété comme le début d’un spécificateur de formatage alors que c’est juste le symbole littéral du pourcentage.
Pour faire reconnaître le signe %
, la syntaxe des chaînes formatées est %%
:
1 2 | p = 10
print("Inflation : %d%% par an" %p)
|
3 | Inflation : 10% par an
|
- Ligne 2 : Pour lire sans ambiguïté le signe
%
, la syntaxe Python exige qu’on fasse apparaître%
sous la forme%%
dans la chaîne formatée.
Alternative¶
On aurait pu aussi résoudre le problème de la manière suivante
1 2 | s = "Inflation : %d%s par an" %(10, "%")
print(s)
|
3 | Inflation : 10% par an
|
Échappement¶
Ainsi, le caractère %
joue un rôle d’échappement de lui même. Noter que le caractère \
d’échappement habituel ne fonctionne pas :
1 2 | p = 10
print("Inflation : %d\% par an" %p)
|
3 4 | print("Inflation : %d\% par an" %p)
TypeError: not enough arguments for format string
|
Formatage de chaînes et dictionnaire¶
Dans une chaîne formatée, après l’opérateur %
, on trouve un conteneur où se trouvent les valeurs de remplacement. Le cas déjà rencontré est celui d’un conteneur qui est un tuple.
Un dictionnaire dont les clés sont des chaînes de caractères peut aussi être utilisé pour formater des chaînes :
1 2 3 4 5 6 7 | gabarit = "Le langage %(langage)s existe depuis %(date)d"
dico1 ={'langage': 'Python', "date":1991}
print(gabarit %dico1)
dico2 ={'langage': 'C', "date":1972, "auteur": "Ritchie"}
print(gabarit %dico2)
|
8 9 | Le langage Python existe depuis 1991
Le langage C existe depuis 1972
|
Ici, on dispose du gabarit :
Le langage NOM existe depuis DATE
où NOM est à remplacer par une chaîne et DATE par un entier.
La chaîne formatée correspondant à ce gabarit est le format suivant :
"Le langage %(langage)s existe depuis %(date)d"
On observe que dans le format, les marqueurs %
sont suivis de parenthèses contenant une chaîne, ici langage et date. Le format s’utilise en écrivant
format %dico
où dico
est un dictionnaire contenant au moins une clé "langage"
et une clé "date"
dont les noms correspondent aux noms entre les parenthèses dans les spécificateur de formatage.
Chaque valeur à remplacer dans format
est signalée par un marqueur %
suivi
- de la clé du dictionnaire dont la valeur va servir de remplacement
- d’une lettre (ici
s
etd
) qui indique la conversion effectuée, icis
pour string etd
pour entier décimal.
Comparaison avec d’autres styles de formatage¶
Malgré l’ancienneté du format, le format précédent est peut-être le plus lisible des formats disponibles. Comparons.
D’abord le formatage classique que l’onvient de voir :
1 2 3 4 5 6 7 | dico1 ={'langage': 'Python', "date":1991}
dico2 ={'langage': 'C', "date":1972, "auteur": "Ritchie"}
gabarit = "Le langage %(langage)s existe depuis %(date)d"
print(gabarit %dico1)
print(gabarit %dico2)
|
Le formatage avec la méthode format
:
1 2 3 4 5 6 7 | dico1 ={'langage': 'Python', "date":1991}
dico2 ={'langage': 'C', "date":1972, "auteur": "Ritchie"}
gabarit = "Le langage {0[langage]} existe depuis {0[date]}"
print(gabarit.format(dico1))
print(gabarit.format(dico2))
|
Le formatage avec des f-chaînes :
1 2 3 4 5 6 7 8 | dico1 ={'langage': 'Python', "date":1991}
dico2 ={'langage': 'C', "date":1972, "auteur": "Ritchie"}
f1 = f"Le langage {dico1['langage']} existe depuis {dico1['date']}"
f2 = f"Le langage {dico2['langage']} existe depuis {dico2['date']}"
print(f1)
print(f2)
|
Champ¶
Notion de champ¶
L’exemple ci-dessous illustre la notion de champ dans un formatage :
1 2 | s = "xxxxxxx%5dxxxxxxxxx" %42
print(s)
|
3 | xxxxxxx 42xxxxxxxxx
|
On peut placer la valeur de remplacement (ici 42) à l’intérieur d’un champ qui est tout simplement une zone de texte présente dans la chaîne à construire et ayant une certaine largeur (ici 5), dite largeur du champ. La valeur de remplacement est placée dans le champ, alignée à droite et cette valeur est précédée d’espaces dans le champ.
Il se peut que la largeur du champ soit trop petite pour la valeur donnée et dans ce cas la valeur de remplacement sera complètement placée et la largeur sera ignorée :
1 2 | s = "xxxxxxx%5dxxxxxxxxx" %9999999
print(s)
|
3 | xxxxxxx9999999xxxxxxxxx
|
Les champs fonctionnent pour tout type de valeur (des entiers, des chaînes, etc):
1 2 | s = "xxxxxxx%10sxxxxxxxxx" %"TOTO"
print(s)
|
3 | xxxxxxx TOTOxxxxxxxxx
|
Placement à gauche du champ¶
La valeur de remplacement dans un champ est, par défaut, alignée à droite. Une option permet d’aligner à gauche.
Si on place un signe -
après le signe %
, la valeur est placée à gauche du champ et est suivie d’espaces :
1 2 | s = "xxxxxxx%-5dxxxxxxxxx" %42
print(s)
|
3 | xxxxxxx42 xxxxxxxxx
|
Ce type d’option est appelé drapeau de conversion (conversion flag).
Zéros dominants¶
Une option de champ permet de faire précéder la valeur de remplacement d’un nombre par un certain nombre de zéros :
1 2 | s = "James Bond %09d est anglais"%7
print(s)
|
3 | James Bond 000000007 est anglais
|
- Ligne 1 : le champ a pour largeur 9 et la valeur de remplacement (ici 7) sera précédée dans le champ par des zéros
Ce type d’option est appelé drapeau.
Formatage à champ variable¶
Ls chaînes formatées classiques proposent une syntaxe afin de créer des champs de longueur variable.
Au lieu d’écrire
1 2 | s = "xxxxxxxxx%10dxxxxxx" %(42)
print(s)
|
3 | xxxxxxxxx 42xxxxxx
|
on peut écrire
1 2 | s = "xxxxxxxxx%*dxxxxxx" %(10, 42)
print(s)
|
3 | xxxxxxxxx 42xxxxxx
|
Noter le symbole *
avant le type de conversion (d
). La valeur de la largeur est présente dans le tuple juste avant la valeur de remplacement.
L’avantage de la deuxième forme (avec *
) est que le champ a alors une largeur (ici 10) que l’on peut rendre variable ce qui peut être intéressant puisqu’on peut donner un champ qui va dépendre de la donnée formatée (ici 42).
La largeur est placée dans un tuple juste avant la valeur à afficher. On a donc ici deux valeurs dans le tuple mais une seule valeur affichée.
Voici un exemple où la largeur de champ est vraiment variable :
1 2 3 4 5 6 | gabarit = "..........%*s............."
for z in ["toto", "azertyuiop"]:
s = gabarit %(3 * len(z), z)
print(s)xxxxxx%*sxxxxxx" %(3 * len(z), z)
print(s)
|
7 8 | .......... toto.............
.......... azertyuiop.............
|
Il se peut que plusieurs champs soient variables :
1 2 | s = "xxxx%*sxxx%*dxx%4dx" %(10,"TOTO", 5, 42, 81)
print(s)
|
3 | xxxx TOTOxxx 42xx 81x
|
Ici, on a affiché trois valeurs TOTO, 42 et 1000. Le deux premières sont à champ variable et la largeur du champ (ici 10 puis 5) apparait dans le tuple juste avant la valeur à afficher. Noter que la dernière a un champ non variable.
Pour chaque spécificateur de format qui commence par *
, c’est d’abord la largeur qui est capturée dans le tuple puis la valeur de remplacement.
On peut utiliser un champ variable pour contrôler la partie décimale d’un flottant :
1 2 3 4 5 | from math import pi
print("%.*f"%(8,pi))
print("%.*f"%(6, pi))
print()
|
6 7 | 3.14159265
3.141593
|
On peut d’ailleurs résoudre le problème sans recours à cette nouvelle syntaxe :
1 2 3 4 | from math import pi
for precision in [8,6]:
print("%%.%sf" % precision %pi)
|
5 6 | 3.14159265
3.141593
|
Cumuls d’options¶
On peut cumuler différentes options de formatage. Par exemple :
1 2 | x = 3.1415926
print("pi = %10.2f (approximation)" % x)
|
3 | pi = 3.14 (approximation)
|
- Ligne 2 : cumul de champ et de précision à deux décimales
1 2 | x = 3.1415926
print("pi = %-10.2f (approximation)" % x)
|
3 | pi = 3.14 (approximation)
|
- Ligne 2 : cumul de champ (10), d’alignement à gauche (le signe
-
) et de précision à deux décimales (.2
)
Nombres¶
Espace automatique devant un nombre positif¶
On peut placer un espace devant une valeur numérique formatée en plaçant un espace après le signe %
dans le format :
1 2 3 4 5 | gabarit = "xxxxxxx% dxxxxxxxxx"
s = gabarit %42
t = gabarit %-42
print(s)
print(t)
|
6 7 | xxxxxxx 42xxxxxxxxx
xxxxxxx-42xxxxxxxxx
|
L’intérêt est de faire des alignements verticaux avec des nombres négatifs car en cas de nombre négatif, aucune espace n’est placée.
Sans cette option, l’alignement n’est pas correct :
1 2 3 4 5 | gabarit = "xxxxxxx%dxxxxxxxxx"
s = gabarit %42
t = gabarit %-42
print(s)
print(t)
|
6 7 | xxxxxxx42xxxxxxxxx
xxxxxxx-42xxxxxxxxx
|
Ce type d’option est appelé drapeau.
Option de signe¶
Bien sûr, le formatage d’un nombre négatif impose un signe -
devant le nombre formaté. Mais, par défaut, un nombre positif est formaté sans être précédé d’un signe, +
:
1 2 3 4 5 | gabarit = "x = %d"
s = gabarit %42
t = gabarit %-42
print(s)
print(t)
|
6 7 | x = 42
x = -42
|
On peut forcer le placement d’un signe +
devant une valeur numérique positive formatée en plaçant un signe +
après le signe %
dans le spécificateur :
1 2 3 4 5 | gabarit = "x = %+d"
s = gabarit %42
t = gabarit %-42
print(s)
print(t)
|
6 7 | x = +42
x = -42
|
L’effet est de permettre des alignement verticaux.
Ce type d’option est appelé drapeau.
Conversion d’un flottant avec %d
¶
Le spécificateur %d
appliqué à un flottant renvoie le nombre privé de sa partie décimale :
1 2 3 4 | x = 421.99
print("%d" %x)
print("%d" %(-x))
|
5 6 | 421
-421
|
Formatage en bases 8 ou 16¶
Il est possible de formater une chaîne pour que les entiers apparaissent représentés en base 16 ou en base 8.
Pour la base 16, le spécificateur est %x
ou %X
:
1 2 3 4 | s = "%d (base 10) = %x (base 16)" %(421, 421)
t = "%d (base 10) = %X (base 16)" %(421, 421)
print(s)
print(t)
|
5 6 | 421 (base 10) = 1a5 (base 16)
421 (base 10) = 1A5 (base 16)
|
On notera que les lettres hexadécimales sont formatées en minuscule avec le type x
et en majuscule avec le type X
.
Pour la base 8, le spécificateur est %o
(la lettre o
minuscule) :
1 2 | s = "%d (base 10) = %o (base 8)" %(421, 421)
print(s)
|
3 | 421 (base 10) = 645 (base 8)
|
Par contre, il n’existe pas de caractère de conversion vers d’autres bases (comme la base 2 par exemple).
Formes alternées¶
La forme alternée est une syntaxe utilisant le caractère #
dans un spécificateur de formatage et permettant, dans les cas les plus fréquents, un formatage en base 8 ou 16. Par exemple :
1 2 3 4 | x = 42
print("%x" %x)
print("%#x" %x)
|
5 6 | 2a
0x2a
|
- Ligne 4 : la forme alternée préfixe la représentation brute de la ligne 3
Les formes alternées les plus utilisées concernent l’ajout de préfixe dans le formatage avec le type o (octal) et les types x ou X (hexadécimal).
Le caractère #
se place juste après le signe %
sauf s’il y a une clé de dictionnaire pour le remplacement, auquel cas il se place juste après :
1 2 3 | dico = {"my_x" : 42, "y" : 421}
print("%(my_x)#x" %dico)
|
4 | 0x2a
|
Ce type d’option est appelé drapeau.
Formatage d’un flottant en notation scientifique¶
Les spécificateurs de type %e
ou %E
formatent un nombre en notation scientifique :
1 2 3 4 5 | x = 2030.45263
s = "%f (<- point décimal) = %e (<- ingenieur)" %(x,x)
t = "%f (<- point décimal) = %E (<- ingenieur)" %(x,x)
print(s)
print(t)
|
6 7 | 2030.452630 (<- point décimal) = 2.030453e+03 (<- ingenieur)
2030.452630 (<- point décimal) = 2.030453E+03 (<- ingenieur)
|
Divers¶
Méthode classique : statut, documentation¶
La méthode classique de formatage de chaîne est basée sur le style des chaînes formatées du langage C ou de Java utilisant l’opérateur %
de substitution.
Selon la Documentation officielle :
- le système classique comprendrait des « bizarreries » qui conduiraient à un certain nombre d’erreurs
- la nouvelle syntaxe permet d’éviter ces erreurs mais qu’elle possède aussi ses inconvénients.
La documentation des versions 3.1 et 3.2 de Python affirmait :
The formatting operations described here are obsolete and may go away in future versions of Python. Use the new String Formatting in new code.
Toutefois cette mention a disparu des versions suivantes. A propos de cette disparition, on pourra lire la discussion Why was the warning about % formatting toned down in newer Python docs?.
La question de l’obsolescence du système classique reste posée et discutée.
A signaler (2021) que les chaînes binaires utilisent la méthode classique et qu’aucune méthode analogue à format
ou les f-chaînes n’est envisagée, comme indiqué ici.
Liens vers la documentation :
Utilisation des chaînes formatées classiques¶
Le formatage pour créer une nouvelle chaîne¶
Une chaîne formatée est une chaîne comme les autres. Elle n’est pas exclusivement destinée à être affichée, bien que ce soit assez fréquent. Une chaîne formatée possède toutes les propriétés d’une chaîne, par exemple une longueur :
1 2 3 4 5 6 7 8 | modele = "Son nom est %s et il a %s ans."
naissance = 2000
aujourdhui = 2030
a = modele %("Arthur", aujourdhui- naissance)
print(len(a))
print(a)
|
9 10 | 34
Son nom est Arthur et il a 30 ans.
|
Donc, le formatage de chaîne est un outil de construction de nouvelles chaînes.
Usage typique¶
Les chaînes formatées servent souvent à remplacer des valeurs dans une chaîne-type puis à effectuer l’affichage (en général avec print
). Par exemple :
1 2 3 4 5 6 | modele = "%s = %s, %s = %s => %s + %s = %s"
x=42
y=18
print(modele %("x", x, "y", y, "x", "y", x+y))
print(modele %("toto", x, "titi", y, "toto", "titi", x+y))
|
7 8 | x = 42, y = 18 => x + y = 60
toto = 42, titi = 18 => toto + titi = 60
|
Exemple avancé¶
Les chaînes formatées servent aussi à construire des chaînes complexes, représentant par exemple des alignements particuliers, pas forcément dans un but immédiat d’affichage, typiquement, pour réaliser une table de multiplication comme ceci :
---------------------------------------------------------------------
| 1 x 1 = 1| 2 x 1 = 2| 3 x 1 = 3| 4 x 1 = 4| 5 x 1 = 5|
| 1 x 2 = 2| 2 x 2 = 4| 3 x 2 = 6| 4 x 2 = 8| 5 x 2 = 10|
| 1 x 3 = 3| 2 x 3 = 6| 3 x 3 = 9| 4 x 3 = 12| 5 x 3 = 15|
| 1 x 4 = 4| 2 x 4 = 8| 3 x 4 = 12| 4 x 4 = 16| 5 x 4 = 20|
| 1 x 5 = 5| 2 x 5 = 10| 3 x 5 = 15| 4 x 5 = 20| 5 x 5 = 25|
| 1 x 6 = 6| 2 x 6 = 12| 3 x 6 = 18| 4 x 6 = 24| 5 x 6 = 30|
| 1 x 7 = 7| 2 x 7 = 14| 3 x 7 = 21| 4 x 7 = 28| 5 x 7 = 35|
| 1 x 8 = 8| 2 x 8 = 16| 3 x 8 = 24| 4 x 8 = 32| 5 x 8 = 40|
| 1 x 9 = 9| 2 x 9 = 18| 3 x 9 = 27| 4 x 9 = 36| 5 x 9 = 45|
| 1 x 10 = 10| 2 x 10 = 20| 3 x 10 = 30| 4 x 10 = 40| 5 x 10 = 50|
---------------------------------------------------------------------
| 6 x 1 = 6| 7 x 1 = 7| 8 x 1 = 8| 9 x 1 = 9|10 x 1 = 10|
| 6 x 2 = 12| 7 x 2 = 14| 8 x 2 = 16| 9 x 2 = 18|10 x 2 = 20|
| 6 x 3 = 18| 7 x 3 = 21| 8 x 3 = 24| 9 x 3 = 27|10 x 3 = 30|
| 6 x 4 = 24| 7 x 4 = 28| 8 x 4 = 32| 9 x 4 = 36|10 x 4 = 40|
| 6 x 5 = 30| 7 x 5 = 35| 8 x 5 = 40| 9 x 5 = 45|10 x 5 = 50|
| 6 x 6 = 36| 7 x 6 = 42| 8 x 6 = 48| 9 x 6 = 54|10 x 6 = 60|
| 6 x 7 = 42| 7 x 7 = 49| 8 x 7 = 56| 9 x 7 = 63|10 x 7 = 70|
| 6 x 8 = 48| 7 x 8 = 56| 8 x 8 = 64| 9 x 8 = 72|10 x 8 = 80|
| 6 x 9 = 54| 7 x 9 = 63| 8 x 9 = 72| 9 x 9 = 81|10 x 9 = 90|
| 6 x 10 = 60| 7 x 10 = 70| 8 x 10 = 80| 9 x 10 = 90|10 x 10 = 100|
---------------------------------------------------------------------
La table de multiplication est placée dans une grande chaîne au fur et à mesure. Ensuite, cette chaîne est affichée en une seule instruction.
Générer des formats¶
L’échappement du caractère %
est utile, par exemple, pour générer des formats :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | formatFormat = "Son nom est %%%s et il a %%%s ans"
print(formatFormat)
print()
format_s_d = formatFormat %('s', 'd')
print(format_s_d)
t = ("Alfred", 100)
print(format_s_d %t)
print()
format_s_f = formatFormat %('s', 'f')
print(format_s_f)
t = ("Alfred", 100)
print(format_s_f %t)
|
17 18 19 20 21 22 23 | Son nom est %%%s et il a %%%s ans
Son nom est %s et il a %d ans
Son nom est Alfred et il a 100 ans
Son nom est %s et il a %f ans
Son nom est Alfred et il a 100.000000 ans
|
Supposons que la chaîne formatFormat
(ligne 1) soit utilisée comme un format dans une chaîne de formatage (cf. lignes 6 ou 13). Alors, la suite %%%s
se décompose en :
%%
qui va produire le caractère littéral%
dans la chaîne formatée produite%s
qui est un spécificateur de formatage et qui va subir un remplacement (plus bas, par la lettres
ou encore la lettref
)
Ainsi, la chaîne formatFormat
peut être utilisée comme format qui produit un format (par exemple, format_s_d
) qui lui-même peut être utilisé pour obtenir une chaîne formatée.
Troncature de caractères¶
On peut formater une chaîne en en conservant qu’un préfixe de longeur donnée :
1 | print("Le 19 %.3s 2038" %"janvier")
|
2 | Le 19 jan 2038
|
Dans un spécificateur, un point suivi d’une valeur entière \(n\geq 0\) dans un formatage de type de conversion s
(chaîne) entraîne la troncature à droite pour ne garder que les \(n\) premiers caractères.
Syntaxe complète¶
Un spécificateur de formatage peut contenir jusqu’à 5 options sans compter la lettre finale pour le type de conversion.
Voici un exemple utilisant un dictionnaire :
1 2 3 | dico = {"nom":"Alfred", "age": 100}
s = "Son nom est %(nom)s et il a %(age)0 9.3f ans" %dico
print(s)
|
4 | Son nom est Alfred et il a 0100.000 ans
|
Le spécificateur %(age)0 9.3f
formate un flottant (à cause du type de conversion f
) et admet la séquence d’options (age)0 9.3
et qui se décompose ainsi :
(age)
qui est une clé du dictionnairedico
et qui est opérande de l’opérateur%
(ligne 2)0
qui spécifie que le formatage du nombre pourra commencer par des zéros- l’espace suivant place un espace devant le nombre s’il est positif (comme on peut le voir dans la sortie).
9
est une largeur de champ.3
est un indicateur de précision à 3 décimales.
Voici un exemple utilisant un tuple :
1 2 3 | t = ("Alfred", 11, 100)
s = "Son nom est %s et il a %#0 *x ans" %t
print(s)
|
4 | Son nom est Alfred et il a 0x00000064 ans
|
Le spécificateur %#0 *.3x
formate en hexadécimal un entier (à cause du type de conversion x
) et admet la séquence d’options #0 *.3
et qui se décompose ainsi :
0
qui spécifie que le formatage du nombre pourra commencer par des zéros#
forme alternée qui préfixe le formatage du nombre par0x
- l’espace suivant place un espace devant le nombre s’il est positif
*
est une largeur de champ variable (11
ici) et qui est lue dans le tuple.
Ordre des spécificateurs¶
Les éléments d’un spécificateur doivent être donnés dans l’ordre suivant :
- premier caractère :
%
- dernier caractère : une unique lettre (
d
,s
,f
,x
,X
, etc) désignant le type de conversion - si les données à remplacer proviennent d’un dictionnaire, la clé de remplacement doit apparaître juste après le signe
%
- ensuite, on place un ou plusieurs éventuels drapeaux
#
,0
, un espace ou les signes-
ou+
et qui ont un rôle de formatage en position préfixe du remplacement - ensuite, une éventuelle largeur de champ, éventuellement variable si on utilise le caractère
*
- enfin une précision formée d’un point et d’un entier définissant la troncature à droite, soit en décimales si le type de conversion est flottant (
f
) soit en caractères si le type de conversion est chaîne (s
)
Formatage classique et concaténation¶
Le formatage de chaînes permet accessoirement de concaténer des chaînes
1 2 3 4 5 | modele = "%s%s%s"
print(modele %("Uni","Ver","Sel"))
modele = "%s-%s-%s"
print(modele %("Uni","Ver","Sel"))
|
6 7 | UniVerSel
Uni-Ver-Sel
|