Python 2.6 führte die str.format()
Methode mit einer etwas anderen Syntax als der vorhandene %
Operator ein. Was ist besser und für welche Situationen?
Im Folgenden wird jede Methode verwendet und das gleiche Ergebnis erzielt. Was ist also der Unterschied?
#!/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!"
Wann erfolgt die Formatierung von Zeichenfolgen in Python? Wenn beispielsweise meine Protokollierungsstufe auf HIGH eingestellt ist, kann ich trotzdem einen Treffer für die Ausführung des folgenden
%
Vorgangs erzielen? Und wenn ja, gibt es eine Möglichkeit, dies zu vermeiden?log.debug("some debug info: %s" % some_info)
python
performance
logging
string-formatting
f-string
NorthIsUp
quelle
quelle
%
Stil häufiger, denn wenn Sie die verbesserten Funktionen desformat()
Stils nicht benötigen , ist der%
Stil oft viel praktischer.format()
Formatierungsstil und den älteren%
Formatierungsstil .Antworten:
Um Ihre erste Frage zu beantworten ...
.format
scheint in vielerlei Hinsicht anspruchsvoller zu sein. Eine nervige Sache%
ist auch, wie es entweder eine Variable oder ein Tupel aufnehmen kann. Sie würden denken, dass Folgendes immer funktionieren würde:doch wenn es
name
passiert,(1, 2, 3)
wird es ein werfenTypeError
. Um sicherzustellen, dass es immer gedruckt wird, müssen Sie dies tunDas ist einfach hässlich.
.format
hat diese Probleme nicht. Auch im zweiten Beispiel, das Sie gegeben haben,.format
sieht das Beispiel viel sauberer aus.Warum würdest du es nicht benutzen?
Um Ihre zweite Frage zu beantworten, erfolgt die Zeichenfolgenformatierung gleichzeitig mit jeder anderen Operation - wenn der Zeichenfolgenformatierungsausdruck ausgewertet wird. Und Python, das keine faule Sprache ist, wertet Ausdrücke aus, bevor Funktionen aufgerufen werden. In Ihrem
log.debug
Beispiel wird der Ausdruck also"some debug info: %s"%some_info
zuerst ausgewertet, z. B."some debug info: roflcopters are active"
wird diese Zeichenfolge übergebenlog.debug()
.quelle
"%(a)s, %(a)s" % {'a':'test'}
log.debug("something: %s" % x)
aber nicht für verschwenden.log.debug("something: %s", x)
Die Formatierung der Zeichenfolge wird in der Methode behandelt und Sie erhalten keinen Leistungseinbruch, wenn sie nicht protokolliert wird. Wie immer antizipiert Python Ihre Bedürfnisse =)'{0}, {0}'.format('test')
.man sprintf
und erfahren Sie mehr über die$
Notation in%
Platzhalternprintf("%2$d", 1, 3)
"3" ausdrucken möchten , ist dies in POSIX angegeben, nicht in C99. In der Manpage, auf die Sie verwiesen haben, heißt es: "Der C99-Standard enthält den Stil nicht mit '$' ...".Etwas, das der Modulo-Operator (%) nicht kann, afaik:
Ergebnis
Sehr hilfreich.
Ein weiterer Punkt: Als
format()
Funktion kann sie als Argument in anderen Funktionen verwendet werden:Ergebnisse in:
quelle
map
genauso einfach wie das Formatieren verwenden.map('some_format_string_%s'.__mod__, some_iterable)
printf("%2$s %1$s\n", "One", "Two");
kompiliert mitgcc -std=c99 test.c -o test
, die Ausgabe istTwo One
. Aber ich stehe korrigiert da: Es ist eigentlich eine POSIX-Erweiterung und nicht C. Ich kann sie im C / C ++ - Standard nicht wiederfinden, wo ich dachte, ich hätte sie gesehen. Der Code funktioniert sogar mit dem Standardflag 'c90'.sprintf
Manpage . Dies listet es nicht auf, ermöglicht es libs jedoch, eine Obermenge zu implementieren. Mein ursprüngliches Argument ist immer noch gültig und ersetztC
durchPosix
%
zum Neuordnen von Platzhaltern verwenden. Ich möchte diesen ersten Kommentar aus Gründen der Kommentarkonsistenz hier immer noch nicht löschen. Ich entschuldige mich dafür, dass ich meine Wut hier abgelegt habe. Es richtet sich gegen die oft gemachte Aussage, dass die alte Syntax per se dies nicht zulassen würde. Anstatt eine völlig neue Syntax zu erstellen, hätten wir die Standard-Posix-Erweiterungen einführen können. Wir könnten beides haben.Angenommen, Sie verwenden das Python-
logging
Modul, können Sie die Argumente für die Zeichenfolgenformatierung als Argumente an die.debug()
Methode übergeben, anstatt die Formatierung selbst vorzunehmen:Dadurch wird die Formatierung vermieden, es sei denn, der Logger protokolliert tatsächlich etwas.
quelle
log.debug("some debug info: %(this)s and %(that)s", dict(this='Tom', that='Jerry'))
Sie können hier jedoch nicht die neue.format()
Stilsyntax verwenden, auch nicht in Python 3.3, was eine Schande ist.Ab Python 3.6 (2016) können Sie Variablen durch f-Strings ersetzen:
Beachten Sie das
f"
Präfix. Wenn Sie dies in Python 3.5 oder früher versuchen, erhalten Sie eineSyntaxError
.Siehe https://docs.python.org/3.6/reference/lexical_analysis.html#f-strings
quelle
PEP 3101 schlägt vor, den
%
Operator durch die neue, erweiterte Zeichenfolgenformatierung in Python 3 zu ersetzen , wo dies die Standardeinstellung wäre.quelle
.format
nicht die%
Formatierung von Zeichenfolgen.Aber bitte seien Sie vorsichtig, gerade habe ich ein Problem entdeckt, als ich versuchte, alle
%
durch.format
vorhandenen Code zu ersetzen :'{}'.format(unicode_string)
Ich werde versuchen, unicode_string zu codieren, und es wird wahrscheinlich fehlschlagen.Schauen Sie sich einfach dieses interaktive Python-Sitzungsprotokoll an:
s
ist nur eine Zeichenfolge (in Python3 als "Byte-Array" bezeichnet) undu
eine Unicode-Zeichenfolge (in Python3 als "Zeichenfolge" bezeichnet):Wenn Sie dem
%
Operator ein Unicode-Objekt als Parameter geben, wird eine Unicode-Zeichenfolge erzeugt, auch wenn die ursprüngliche Zeichenfolge nicht Unicode war:Die
.format
Funktion löst jedoch "UnicodeEncodeError" aus:und es funktioniert nur dann mit einem Unicode-Argument, wenn die ursprüngliche Zeichenfolge Unicode war.
oder wenn die Argumentzeichenfolge in eine Zeichenfolge konvertiert werden kann (sogenanntes 'Byte-Array')
quelle
format
Methode werden wirklich benötigt ...%
String-Interpolation jemals verschwinden würde."p1=%s p2=%d" % "abc", 2
oder"p1=%s p2=%s" % (tuple_p1_p2,)
. Sie könnten denken, es ist die Schuld des Codierers, aber ich denke, es ist nur eine seltsame fehlerhafte Syntax, die für das Quicky-Scriptie gut aussieht, aber für den Produktionscode schlecht ist.%s
,%02d
wie"p1=%s p2=%02d".format("abc", 2)
. Ich beschuldige diejenigen, die die Formatierung der geschweiften Klammern erfunden und genehmigt haben, die Sie brauchen, um ihnen zu entkommen,{{}}
und die imho hässlich aussehen.Ein weiterer Vorteil von
.format
(den ich in den Antworten nicht sehe): Es kann Objekteigenschaften annehmen.Oder als Schlüsselwortargument:
%
Soweit ich das beurteilen kann, ist dies nicht möglich .quelle
'x is {0}, y is {1}'.format(a.x, a.y)
. Sollte nur verwendet werden, wenn diea.x
Operation sehr kostspielig ist.'x is {a.x}, y is {a.y}'.format(a=a)
. Lesbarer als beide Beispiele.'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}
oder was auch immer er möchte. Dies ist weitaus sauberer als der Versuch, die gleiche Funktionalität wie der alte Formatierer anzubieten. Es macht vom Benutzer bereitgestellte Formatzeichenfolgen viel leistungsfähiger.%
gibt bessere Leistung alsformat
aus meinem Test.Testcode:
Python 2.7.2:
Ergebnis:
Python 3.5.2
Ergebnis
Es sieht in Python2 so aus, der Unterschied ist gering, während es in Python3
%
viel schneller ist alsformat
.Vielen Dank an Chris Cogdon für den Beispielcode.
Bearbeiten 1:
Im Juli 2019 erneut in Python 3.7.2 getestet.
Ergebnis:
Es gibt keinen großen Unterschied. Ich denke, Python verbessert sich allmählich.
Bearbeiten 2:
Nachdem jemand den F-String von Python 3 im Kommentar erwähnt hatte, führte ich unter Python 3.7.2 einen Test für den folgenden Code durch:
Ergebnis:
Es scheint, dass F-String immer noch langsamer als,
%
aber besser als istformat
.quelle
str.format
mehr Funktionen (insbesondere typspezifische Formatierung, z'{0:%Y-%m-%d}'.format(datetime.datetime.utcnow())
. B. ). Leistung kann nicht die absolute Voraussetzung für alle Jobs sein. Verwenden Sie das richtige Werkzeug für den Job.%
erlaubt der Bediener,printf
Wissen wiederzuverwenden ; Die Wörterbuchinterpolation ist eine sehr einfache Erweiterung des Prinzips.Wie ich heute entdecken, über die alte Art und Weise Saiten der Formatierung
%
nicht unterstütztDecimal
, Python - Modul für dezimal festen Punkt und Gleitkomma - Arithmetik, aus dem Kasten heraus .Beispiel (mit Python 3.3.5):
Ausgabe:
Möglicherweise gibt es Workarounds, aber Sie können die
format()
Methode trotzdem sofort anwenden .quelle
str(d)
vor dem Erweitern des Parameters aufgerufen werden, während Formatierungen im alten Stil wahrscheinlichfloat(d)
zuerst aufgerufen werden .str(d)
kehrt zurück"3.12375239e-24"
, nicht"0.00000000000000000000000312375239000000000000000000"
Wenn Ihr Python> = 3.6 ist, ist das F-String-formatierte Literal Ihr neuer Freund.
Es ist einfacher, sauberer und leistungsfähiger.
quelle
Nebenbei bemerkt, Sie müssen keinen Leistungseinbruch hinnehmen, um die Formatierung im neuen Stil für die Protokollierung zu verwenden. Sie können eine beliebiges Objekt zu übergeben
logging.debug
,logging.info
usw. , dass Geräte der__str__
magischen Methode. Wenn das Protokollierungsmodul entschieden hat, dass es Ihr Nachrichtenobjekt (was auch immer es sein soll) ausgeben muss, ruft esstr(message_object)
vorher auf. Sie könnten also so etwas tun:Dies alles wird in der Python 3-Dokumentation beschrieben ( https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles ). Es funktioniert jedoch auch mit Python 2.6 ( https://docs.python.org/2.6/library/logging.html#using-arbitrary-objects-as-messages ).
Einer der Vorteile dieser Technik, abgesehen von der Tatsache, dass sie im Formatierungsstil agnostisch ist, besteht darin, dass sie verzögerte Werte zulässt, z. B. die
expensive_func
obige Funktion . Dies bietet eine elegantere Alternative zu den Ratschlägen in den Python-Dokumenten hier: https://docs.python.org/2.6/library/logging.html#optimization .quelle
format
ohne Leistungseinbußen - dies geschieht durch genaues Überschreiben__str__
wie vorgesehenlogging
- verkürzt den Funktionsaufruf auf einen einzelnen Buchstaben (N
), der sich einigen der Standardmethoden zum Definieren von Zeichenfolgen sehr ähnlich anfühlt - UND ermöglicht Faulheit Funktionsaufruf. Vielen Dank! +1logging.Formatter(style='{')
Parameters?Eine Situation, in der dies
%
hilfreich sein kann, ist das Formatieren von Regex-Ausdrücken. Zum Beispiel,erhöht
IndexError
. In dieser Situation können Sie Folgendes verwenden:Dadurch wird vermieden, dass der reguläre Ausdruck als geschrieben wird
'{type_names} [a-z]{{2}}'
. Dies kann nützlich sein, wenn Sie zwei reguläre Ausdrücke haben, von denen einer allein ohne Format verwendet wird, die Verkettung beider jedoch formatiert ist.quelle
'{type_names} [a-z]{{2}}'.format(type_names='triangle|square')
. Es ist wie zu sagen,.format()
kann helfen, wenn Zeichenfolgen verwendet werden, die bereits ein Prozentzeichen enthalten. Sicher. Dann musst du ihnen entkommen."One situation where % may help is when you are formatting regex expressions."
Insbesondere wird angenommen, dassa=r"[a-z]{2}"
es sich um einen Regex-Block handelt, der in zwei verschiedenen Endausdrücken (z . B.c1 = b + a
undc2 = a
) verwendet wird. Angenommen, diesc1
muss bearbeitet werdenformat
(z. B.b
muss die Laufzeit formatiert werden), aberc2
nicht. Dann brauchen Siea=r"[a-z]{2}"
fürc2
unda=r"[a-z]{{2}}"
fürc1.format(...)
.Ich würde hinzufügen, dass wir seit Version 3.6 fstrings wie die folgenden verwenden können
Welche geben
Alles wird in Strings umgewandelt
Ergebnis:
Sie können die Funktion wie in anderen Formaten übergeben
Zum Beispiel geben
quelle
Für Python-Version> = 3.6 (siehe PEP 498 )
quelle
Python 3.6.7 vergleichend:
Ausgabe:
quelle
Aber eine Sache ist, dass auch wenn Sie geschweifte geschweifte Klammern haben, nicht für das Format funktioniert, sondern
%
funktioniert.Beispiel:
quelle