On a reçu un mail du genre :
Salut les mecs!
Je me demandais si il valait mieux utiliser format() ou % quand on veut insérer une variable dans une chaîne?
Je comprend pas vraiment quelle est la différence entre les deux…l’un est-il plus rapide? Plus fiable?Merci les mecs!
Je suppose que d’autres personnes se posent la même question, du coup je poste ça là une bonne fois pour toutes.
En résumé : avec le recul, il n’y en a pas de meilleur. C’est une question de facilité d’usage et de lisibilité.
En effet, %
était parti pour être déprécié en Python 3, mais ce n’est jamais arrivé, pour plusieurs raisons :
%
est souvent plus court à taper.le module
logging
utilise toujours ce format.- avec Python 3.5, le type
bytes
va de nouveau utiliser cet opérateur pour le formatage.
Si votre formatage est simple ou si vous utilisez des bytes ou le module logging
, utilisez %
:
>>> "je suis hyper %s. Brouuuuahhh" % "content" 'je suis hyper content. Brouuuuahhh' |
L’équivalent avec format()
serait :
>>> "je suis hyper {}. Brouuuuahhh".format("content") 'je suis hyper content. Brouuuuahhh' |
On y gagne pas, c’est plus long à taper car il y a plus de lettres mais aussi parce que qu’il y a beaucoup plus de caractères spéciaux à atteindre sur son clavier : {}.()
contre %
.
On table ici sur la facilité et la rapidité d’usage.
Si votre formatage a beaucoup de variables, que vos variables sont déjà dans un dictionnaire, que votre texte est long ou que vous avez besoin de formats avancés, utilisez format()
:
"{value}{unit} ({time:%H:%M:%S})".format(value=3, unit="ppm", time=datetime.now()) '3ppm (10:53:04)' |
L’équivalent avec % serait:
date = datetime.now().strftime("%H:%M:%S") "%(value)s%(unit)s (%(time)s)" % {"value": 3, "unit": "ppm", "time": date} |
Moins lisible, plus verbeux. format()
gagne toujours dès qu’on a un message complexe. Mais ça n’arrive pas aussi souvent qu’on ne le pense, du coup %
a encore de beaux jours devant lui.
Avec Python 3.6 arrivera une nouvelle manière de faire, les f-strings. Si vous avez la chance d’utiliser la 3.6, les f-strings peuvent remplacer avantageusement la plupart des formes ci-dessus :
>>> value = 3 >>> unit = "ppm" >>> f'{value}{unit} ({datetime.now():%H:%M:%S})' '3ppm (10:53:54)' |
Mais il faudra attendre 2016…
Pardon, c’est pas très lisible:
Une autre raison que “c’est comme ça qu’il faut faire” ?
%
marche aussi en python 3Accessoirement certaines syntaxes syntaxe de .format() sont valides en python 3, mais pas en python 2.6
Exemple :
Les 2 ne sont pas plutôt complémentaires sur python 3?
D’ailleurs :
print('yes %s can!' % 'we')
marche très bien sur la 3.3!
Wow, 10 ans de Python et je viens d’apprendre que “%” est conservé en Python 3. J’étais persuadé qu’il était deprecated.
Bon, ça vallait le coup de faire l’article rien que pour ça.
Merci de m’apprendre des trucs tous les jours. Et merci de le faire aussi gentiment.
Oh le mauvais !!! *lapidation*
Par contre je viens d’apprendre de @Romuald que 2.6 ne supportait pas toutes les syntaxes … Content d’avoir toujours utilisé % pour les simples remplacements :)
J’ai cru lire que
%
était un chouilla plus rapide, ne serait-ce que parce qu’il a moins de fonctionnalités.Mais
%
c’est l’héritage des langages C-like, alors que.format()
c’est plus pythonesque. (mais je suis moi aussi une grosse feignasse, à vrai dire)Je ne dis pas que format() n’est pas utile mais perso je n’en ai pas encore eu l’utilité et le % me convient très bien. Clair, rapide à taper et facile à relire et en plus conservé en Python3.
Pourquoi alors se compliquer la vie…?
Mais alors, comment utiliser format si on a un {} dans la chaine à manipuler?
Exemple:
In [20]: "Je veux inserer [0] dans une chaine contenant {zobi=lamouche}".format("ceci")
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
in ()
----> 1 "Je veux inserer [0] dans une chaine contenant {zobi=lamouche}".format("ceci")
KeyError: 'zobi=lamouche'
Terrible!!!
Merci!
format, c’est quand même bien quand dans une substitution, on veut utiliser plusieurs fois un terme
In [2]: print('{0} {0} {0}'.format('bon'))
bon bon bon
C’est aussi mieux pour les variables nommées. %(nom)s c’est plus chiant à tapper que {nom}
Juste une coquille (deux corrections):
feinénants -> fainéants
Salut,
Le “old %-formatting” est déprécié depuis 2.6.
http://docs.python.org/library/stdtypes.html#str.format
C’est ce que je croyais aussi, mais en fait il est toujours là dans les dernières versions de Python 3.
Pour les usages plus avancés, il y a même un DSL de formattage dans “format”
Du coup, on peut séparer la représentation des données, pour les nombres :
Pour faire du padding
Ca évite d’utiliser les “zfills” et companie
On peut même faire des conversions de base pour les nombres (ici du décimal au binaire) :
Plus d’infos : https://docs.python.org/2/library/string.html#format-specification-mini-language
Je suis revenu sur cet article suite à la mise à jour annoncée par mail.
Juste pour rajouter 2 remarques
1) concernant la remarque de Romain sur le fait d’utiliser plusieurs fois le même terme, on peut faire aussi la même chose avec %
=> print “%(x)s %(x)s %(x)s” % {“x” : “bon”}
2) l’équivalent qui affiche la date possède une variable inutile
=> “%(value)s%(unit)s (%(time)s)” % {“value”: 3, “unit”: “ppm”, “time”: datetime.now().strftime(“%H:%M:%S”)}
Ben oui, quand on veut être honnête on essaye d’écrire un code similaire au-moins dans ses variables ;)
Dans ton dernier exemple, la ligne est énorme et illisible, et viole tellement le PEP 8 que Guido hésite a porter plainte pour agression sexuelle. Une ligne comme ça, on la met forcément sur deux lignes.
Et pour les maniaques du slip: https://pyformat.info/.
Cela peut aussi servir :
Quel est l’équivalent avec % ?
Wut ?
Oups l’équivalent avec format() ?
"3a={} 3b={}".format(*vars)
Pour un langage qui proclamait : “There should be one– and preferably only one –obvious way to do it.”, c’est un peu dommage d’avoir maintenant 2 manières presque parfaitement équivalentes de faire la même chose, et qui ne se démarquent que par l’habitude d’utilisation, la place des touches sur le clavier ou la lisibilité dans de très rares cas.
C’est tout le problème de l’innovation et la compatibilité. Si tu veux les deux, ce que Python arrive à faire assez brillament, tu vas forcément payer le prix d’un héritage en API.