Python 2.6 a introduit la str.format()
méthode avec une syntaxe légèrement différente de celle de l' %
opérateur existant . Quelle est la meilleure et pour quelles situations?
Ce qui suit utilise chaque méthode et a le même résultat, alors quelle est la différence?
#!/usr/bin/python sub1 = "python string!" sub2 = "an arg" a = "i am a %s" % sub1 b = "i am a {0}".format(sub1) c = "with %(kwarg)s!" % {'kwarg':sub2} d = "with {kwarg}!".format(kwarg=sub2) print a # "i am a python string!" print b # "i am a python string!" print c # "with an arg!" print d # "with an arg!"
De plus, quand le formatage des chaînes se produit-il en Python? Par exemple, si mon niveau de journalisation est défini sur ÉLEVÉ, vais-je quand même prendre un coup pour effectuer l'
%
opération suivante ? Et si oui, existe-t-il un moyen d'éviter cela?log.debug("some debug info: %s" % some_info)
python
performance
logging
string-formatting
f-string
NorthIsUp
la source
la source
%
style plus ancien plus souvent, car si vous n'avez pas besoin des capacités améliorées duformat()
style, le%
style est souvent beaucoup plus pratique.format()
style mise en forme et plus à%
base de style de formatage .Réponses:
Pour répondre à votre première question ...
.format
semble juste plus sophistiqué à bien des égards. Une chose ennuyeuse%
est également de savoir comment il peut prendre une variable ou un tuple. On pourrait penser que ce qui suit fonctionnerait toujours:pourtant, si
name
cela arrive(1, 2, 3)
, il lancera unTypeError
. Pour garantir qu'il imprime toujours, vous devez fairece qui est tout simplement moche.
.format
n'a pas ces problèmes. Toujours dans le deuxième exemple que vous avez donné, l'.format
exemple est beaucoup plus propre.Pourquoi ne l'utiliseriez-vous pas?
Pour répondre à votre deuxième question, la mise en forme des chaînes se produit en même temps que toute autre opération - lorsque l'expression de mise en forme des chaînes est évaluée. Et Python, n'étant pas un langage paresseux, évalue les expressions avant d'appeler des fonctions, donc dans votre
log.debug
exemple, l'expression"some debug info: %s"%some_info
sera d'abord évaluée, par exemple"some debug info: roflcopters are active"
, puis cette chaîne sera passée àlog.debug()
.la source
"%(a)s, %(a)s" % {'a':'test'}
log.debug("something: %s" % x)
mais pas pourlog.debug("something: %s", x)
La mise en forme des chaînes sera gérée dans la méthode et vous n'obtiendrez pas les performances si elle n'est pas enregistrée. Comme toujours, Python anticipe vos besoins =)'{0}, {0}'.format('test')
.man sprintf
et découvrez la$
notation à l'intérieur des%
espaces réservésprintf("%2$d", 1, 3)
pour imprimer "3", c'est spécifié dans POSIX, pas C99. La page de manuel que vous avez référencée note: «La norme C99 n'inclut pas le style utilisant« $ »…»Quelque chose que l'opérateur modulo (%) ne peut pas faire, afaik:
résultat
Très utile.
Un autre point:,
format()
étant une fonction, peut être utilisé comme argument dans d'autres fonctions:Résulte en:
la source
map
aussi facilement que le format.map('some_format_string_%s'.__mod__, some_iterable)
printf("%2$s %1$s\n", "One", "Two");
compilé avecgcc -std=c99 test.c -o test
, la sortie estTwo One
. Mais je suis corrigé: c'est en fait une extension POSIX et non C. Je ne peux pas la retrouver dans le standard C / C ++, où je pensais l'avoir vue. Le code fonctionne même avec le drapeau std «c90».sprintf
page de manuel . Cela ne le répertorie pas, mais permet aux bibliothèques d'implémenter un sur-ensemble. Mon argument d'origine est toujours valable, en le remplaçantC
parPosix
%
pour réorganiser les espaces réservés. Je voudrais toujours ne pas supprimer ce premier commentaire par souci de cohérence des commentaires ici. Je m'excuse d'avoir évacué ma colère ici. Elle est dirigée contre l'affirmation souvent faite que l'ancienne syntaxe en soi ne le permettrait pas. Au lieu de créer une syntaxe complètement nouvelle, nous aurions pu introduire les extensions std Posix. Nous pourrions avoir les deux.En supposant que vous utilisez le
logging
module de Python , vous pouvez passer les arguments de formatage de chaîne comme arguments à la.debug()
méthode plutôt que de faire le formatage vous-même:ce qui évite de faire le formatage à moins que l'enregistreur n'enregistre réellement quelque chose.
la source
log.debug("some debug info: %(this)s and %(that)s", dict(this='Tom', that='Jerry'))
Cependant, vous ne pouvez pas utiliser la nouvelle.format()
syntaxe de style ici, pas même en Python 3.3, ce qui est dommage.Depuis Python 3.6 (2016), vous pouvez utiliser des chaînes f pour remplacer des variables:
Notez le
f"
préfixe. Si vous essayez ceci dans Python 3.5 ou une version antérieure, vous obtiendrez unSyntaxError
.Voir https://docs.python.org/3.6/reference/lexical_analysis.html#f-strings
la source
PEP 3101 propose de remplacer l'
%
opérateur par le nouveau formatage de chaîne avancé en Python 3, où ce serait la valeur par défaut.la source
.format
ne remplacera pas le%
formatage des chaînes.Mais soyez prudent, je viens de découvrir un problème en essayant de tout remplacer
%
par.format
du code existant:'{}'.format(unicode_string)
va essayer d'encoder unicode_string et échouera probablement.Regardez simplement ce journal de session interactif Python:
s
est juste une chaîne (appelée «tableau d'octets» en Python3) etu
est une chaîne Unicode (appelée «chaîne» en Python3):Lorsque vous donnez un objet Unicode comme paramètre à l'
%
opérateur, il produira une chaîne Unicode même si la chaîne d'origine n'était pas Unicode:mais la
.format
fonction lèvera "UnicodeEncodeError":et cela ne fonctionnera avec un argument Unicode que si la chaîne d'origine était Unicode.
ou si la chaîne d'argument peut être convertie en une chaîne (appelée "tableau d'octets")
la source
format
méthode ne soient vraiment nécessaires ...%
interpolation de chaîne disparaisse."p1=%s p2=%d" % "abc", 2
ou"p1=%s p2=%s" % (tuple_p1_p2,)
. Vous pourriez penser que c'est la faute du codeur, mais je pense que c'est juste une syntaxe défectueuse bizarre qui semble agréable pour le quicky-scriptie mais qui est mauvaise pour le code de production.%s
,%02d
comme"p1=%s p2=%02d".format("abc", 2)
. Je blâme ceux qui ont inventé et approuvé le formatage des accolades bouclés qui a besoin de vous pour leur échapper{{}}
et qui a l'air moche.Encore un autre avantage de
.format
(que je ne vois pas dans les réponses): il peut prendre des propriétés d'objet.Ou, comme argument de mot clé:
Ce n'est pas possible
%
pour autant que je sache.la source
'x is {0}, y is {1}'.format(a.x, a.y)
. Ne doit être utilisé que lorsque l'a.x
opération est très coûteuse.'x is {a.x}, y is {a.y}'.format(a=a)
. Plus lisible que les deux exemples.'x is {a.x}, y is {a.y}'.format(**vars())
'{foo[bar]}'.format(foo={'bar': 'baz'})
.Your order, number {order[number]} was processed at {now:%Y-%m-%d %H:%M:%S}, will be ready at about {order[eta]:%H:%M:%S}
ou ce qu'il veut. C'est beaucoup plus propre que d'essayer d'offrir les mêmes fonctionnalités avec l'ancien formateur. Il rend les chaînes de format fournies par l'utilisateur beaucoup plus puissantes.%
donne de meilleures performances queformat
de mon test.Code de test:
Python 2.7.2:
Résultat:
Python 3.5.2
Résultat
Il regarde en Python2, la différence est petite alors qu'en Python3,
%
est beaucoup plus rapide queformat
.Merci @Chris Cogdon pour l'exemple de code.
Modifier 1:
Testé à nouveau dans Python 3.7.2 en juillet 2019.
Résultat:
Il n'y a pas beaucoup de différence. Je suppose que Python s'améliore progressivement.
Modifier 2:
Après que quelqu'un ait mentionné la f-string de python 3 en commentaire, j'ai fait un test pour le code suivant sous python 3.7.2:
Résultat:
Il semble que la f-string soit encore plus lente
%
mais meilleure queformat
.la source
str.format
donne plus de fonctionnalités (en particulier le formatage spécialisé par exemple'{0:%Y-%m-%d}'.format(datetime.datetime.utcnow())
). La performance ne peut pas être l'exigence absolue de tous les emplois. Utilisez le bon outil pour le travail.%
opérateur permet de réutiliser lesprintf
connaissances; L'interpolation de dictionnaire est une extension très simple du principe.Comme je l'ai découvert aujourd'hui, l'ancienne méthode de formatage des chaînes via
%
ne prend pas en chargeDecimal
le module Python pour l'arithmétique décimale à virgule fixe et à virgule flottante, prêt à l'emploi.Exemple (en utilisant Python 3.3.5):
Production:
Il peut certainement y avoir des solutions, mais vous pouvez toujours envisager d'utiliser la
format()
méthode tout de suite.la source
str(d)
avant d'étendre le paramètre, tandis que la mise en forme de style ancien appelle probablement enfloat(d)
premier.str(d)
revient"3.12375239e-24"
, pas"0.00000000000000000000000312375239000000000000000000"
Si votre python> = 3,6, le littéral au format F-string est votre nouvel ami.
C'est une performance plus simple, propre et meilleure.
la source
En guise de remarque, vous n'avez pas besoin de prendre un coup de performance pour utiliser la nouvelle mise en forme de style avec la journalisation. Vous pouvez passer à tout objet
logging.debug
,logging.info
etc. , qui met en œuvre la__str__
méthode magique. Lorsque le module de journalisation a décidé qu'il doit émettre votre objet message (quel qu'il soit), il appellestr(message_object)
avant de le faire. Vous pouvez donc faire quelque chose comme ceci:Tout cela est décrit dans la documentation Python 3 ( https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles ). Cependant, cela fonctionnera également avec Python 2.6 ( https://docs.python.org/2.6/library/logging.html#using-arbitrary-objects-as-messages ).
Un des avantages de l'utilisation de cette technique, outre le fait qu'elle est indépendante du formatage, est qu'elle permet des valeurs paresseuses, par exemple la fonction
expensive_func
ci-dessus. Cela fournit une alternative plus élégante aux conseils donnés dans les documents Python ici: https://docs.python.org/2.6/library/logging.html#optimization .la source
format
sans affecter les performances - le fait en remplaçant__str__
précisément commelogging
prévu - raccourcit l'appel de fonction à une seule lettre (N
) qui ressemble beaucoup à certaines des méthodes standard pour définir des chaînes - ET permet de paresseux appel de fonction. Je vous remercie! +1logging.Formatter(style='{')
paramètre?Une situation où
%
peut aider est lorsque vous formatez des expressions regex. Par exemple,soulève
IndexError
. Dans cette situation, vous pouvez utiliser:Cela évite d'écrire l'expression régulière sous la forme
'{type_names} [a-z]{{2}}'
. Cela peut être utile lorsque vous avez deux expressions rationnelles, où l'une est utilisée seule sans format, mais la concaténation des deux est formatée.la source
'{type_names} [a-z]{{2}}'.format(type_names='triangle|square')
. C'est comme dire que cela.format()
peut aider lors de l'utilisation de chaînes qui contiennent déjà un pourcentage. Sûr. Vous devez alors leur échapper."One situation where % may help is when you are formatting regex expressions."
Plus précisément, supposez qu'ila=r"[a-z]{2}"
s'agit d'un bloc d'expression régulière que vous utiliserez dans deux expressions finales différentes (par exemplec1 = b + a
etc2 = a
). Supposons que celac1
doit êtreformat
édité (par exempleb
doit être formaté au moment de l'exécution), maisc2
pas. Ensuite, vous avez besoina=r"[a-z]{2}"
dec2
eta=r"[a-z]{{2}}"
pourc1.format(...)
.J'ajouterais que depuis la version 3.6, nous pouvons utiliser des chaînes comme celles-ci
Qui donnent
Tout est converti en chaînes
Résultat:
vous pouvez passer la fonction, comme dans la méthode des autres formats
Donner par exemple
la source
Pour la version python> = 3.6 (voir PEP 498 )
la source
Comparatif Python 3.6.7:
Production:
la source
Mais une chose est que si vous avez des accolades imbriquées, cela ne fonctionnera pas pour le format mais
%
fonctionnera.Exemple:
la source