Frage Python-String-Formatierung:% vs. .format


Python 2.6 führte die str.format() Methode mit einer etwas anderen Syntax als die bestehende % Operator. Was ist besser und für welche Situationen?

  1. Das Folgende verwendet jede Methode und hat das gleiche Ergebnis, also was ist 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!"
    
  2. Wann findet die String-Formatierung in Python statt? Zum Beispiel, wenn mein Logging-Level auf HIGH gesetzt ist, werde ich immer noch einen Treffer machen, um folgendes zu tun % Betrieb? Und wenn ja, gibt es einen Weg dies zu vermeiden?

    log.debug("some debug info: %s" % some_info)
    

1178
2018-02-22 18:46


Ursprung


Antworten:


Um deine erste Frage zu beantworten ... .format scheint in vielerlei Hinsicht ausgeklügelter. Eine nervige Sache % ist auch, wie es entweder eine Variable oder ein Tupel nehmen kann. Sie würden denken, dass das Folgende immer funktionieren würde:

"hi there %s" % name

noch, wenn name ist zufälligerweise (1, 2, 3), wird es werfen TypeError. Um zu garantieren, dass es immer druckt, müssten Sie tun

"hi there %s" % (name,)   # supply the single argument as a single-item tuple

Das ist einfach hässlich. .format hat diese Probleme nicht. Auch im zweiten Beispiel, das du gabst, das .format Beispiel ist viel sauberer aussehen.

Warum würdest du es nicht benutzen?

  • nicht darüber zu wissen (ich vor dem Lesen)
  • muss mit Python 2.5 kompatibel sein

Um Ihre zweite Frage zu beantworten, findet die Formatierung von Zeichenfolgen gleichzeitig mit anderen Operationen statt, wenn der Zeichenfolgenformatierungsausdruck ausgewertet wird. Und Python, das keine faule Sprache ist, wertet Ausdrücke aus, bevor Funktionen aufgerufen werden, also in Ihrem log.debug Beispiel, der Ausdruck "some debug info: %s"%some_infowird zuerst z.B. "some debug info: roflcopters are active", dann wird diese Zeichenfolge an übergeben log.debug().


852
2018-02-22 18:49



Etwas, was der Modulo-Operator (%) nicht kann, afaik:

tu = (12,45,22222,103,6)
print '{0} {2} {1} {2} {3} {2} {4} {2}'.format(*tu)

Ergebnis

12 22222 45 22222 103 22222 6 22222

Sehr hilfreich.

Ein weiterer Punkt: format()kann als Funktion in anderen Funktionen als Argument verwendet werden:

li = [12,45,78,784,2,69,1254,4785,984]
print map('the number is {}'.format,li)   

print

from datetime import datetime,timedelta

once_upon_a_time = datetime(2010, 7, 1, 12, 0, 0)
delta = timedelta(days=13, hours=8,  minutes=20)

gen =(once_upon_a_time +x*delta for x in xrange(20))

print '\n'.join(map('{:%Y-%m-%d %H:%M:%S}'.format, gen))

Ergebnisse in:

['the number is 12', 'the number is 45', 'the number is 78', 'the number is 784', 'the number is 2', 'the number is 69', 'the number is 1254', 'the number is 4785', 'the number is 984']

2010-07-01 12:00:00
2010-07-14 20:20:00
2010-07-28 04:40:00
2010-08-10 13:00:00
2010-08-23 21:20:00
2010-09-06 05:40:00
2010-09-19 14:00:00
2010-10-02 22:20:00
2010-10-16 06:40:00
2010-10-29 15:00:00
2010-11-11 23:20:00
2010-11-25 07:40:00
2010-12-08 16:00:00
2010-12-22 00:20:00
2011-01-04 08:40:00
2011-01-17 17:00:00
2011-01-31 01:20:00
2011-02-13 09:40:00
2011-02-26 18:00:00
2011-03-12 02:20:00

281
2018-06-13 20:20



Angenommen, Sie verwenden Python logging Modul können Sie die String - Formatierungsargumente als Argumente an die übergeben .debug() Methode, anstatt die Formatierung selbst vorzunehmen:

log.debug("some debug info: %s", some_info)

Das vermeidet die Formatierung, es sei denn, der Logger protokolliert tatsächlich etwas.


124
2018-02-22 19:21



Ab Python 3.6 (2016) können Sie verwenden f-Saiten Variablen ersetzen:

>>> origin = "London"
>>> destination = "Paris"
>>> f"from {origin} to {destination}"
'from London to Paris'

Beachten Sie das f" Präfix. Wenn Sie dies in Python 3.5 oder früher versuchen, erhalten Sie eine SyntaxError.

Sehen https://docs.python.org/3.6/reference/lexical_analysis.html#f-strings


88
2018-04-15 11:12



PEP 3101 schlägt die Ersetzung der % Operator mit der neuen, erweiterten String-Formatierung in Python 3, wo dies der Standard wäre.


54
2017-08-01 03:01



Aber sei bitte vorsichtig, gerade jetzt habe ich ein Problem entdeckt, wenn ich versuche, alles zu ersetzen % mit .format im bestehenden Code: '{}'.format(unicode_string) wird versuchen, Unicode_string zu codieren und wird wahrscheinlich fehlschlagen.

Sehen Sie sich dieses interaktive Python-Sitzungsprotokoll an:

Python 2.7.2 (default, Aug 27 2012, 19:52:55) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
; s='й'
; u=u'й'
; s
'\xd0\xb9'
; u
u'\u0439'

s ist nur eine Zeichenfolge (in Python3 'Byte-Array' genannt) und u ist eine Unicode-Zeichenfolge (in Python3 'String' genannt):

; '%s' % s
'\xd0\xb9'
; '%s' % u
u'\u0439'

Wenn Sie ein Unicode-Objekt als Parameter angeben % operator wird eine Unicode-Zeichenkette erzeugt, auch wenn die ursprüngliche Zeichenkette nicht Unicode war:

; '{}'.format(s)
'\xd0\xb9'
; '{}'.format(u)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u0439' in position 0: ordinal not in range(256)

aber die .format Funktion wird "UnicodeEncodeError" auslösen:

; u'{}'.format(s)
u'\xd0\xb9'
; u'{}'.format(u)
u'\u0439'

und es wird mit einem Unicode-Argument nur funktionieren, wenn die ursprüngliche Zeichenfolge Unicode war.

; '{}'.format(u'i')
'i'

oder wenn die Argument-Zeichenfolge in eine Zeichenfolge konvertiert werden kann (so genanntes "Byte-Array")


51
2017-09-03 18:15



Noch ein weiterer Vorteil von .format (was ich nicht in den Antworten sehe): Es kann Objekteigenschaften nehmen.

In [12]: class A(object):
   ....:     def __init__(self, x, y):
   ....:         self.x = x
   ....:         self.y = y
   ....:         

In [13]: a = A(2,3)

In [14]: 'x is {0.x}, y is {0.y}'.format(a)
Out[14]: 'x is 2, y is 3'

Oder als Keyword-Argument:

In [15]: 'x is {a.x}, y is {a.y}'.format(a=a)
Out[15]: 'x is 2, y is 3'

Dies ist nicht möglich mit % Soweit ich sagen kann.


33
2017-12-04 18:33



Wie ich heute entdeckt habe, die alte Art der String-Formatierung über % unterstützt nicht DecimalPythons Modul für Dezimal-Festkomma- und Fließkomma-Arithmetik, out of the box.

Beispiel (mit Python 3.3.5):

#!/usr/bin/env python3

from decimal import *

getcontext().prec = 50
d = Decimal('3.12375239e-24') # no magic number, I rather produced it by banging my head on my keyboard

print('%.50f' % d)
print('{0:.50f}'.format(d))

Ausgabe:

0.00000000000000000000000312375239000000009907464850   0.00000000000000000000000312375239000000000000000000

Es könnte sicherlich Workarounds geben, aber Sie könnten dennoch in Erwägung ziehen, die format() Methode sofort.


27
2018-05-13 17:10