Wie formatiere ich einen String mit einem Wörterbuch in Python-3.x?

215

Ich bin ein großer Fan von Wörterbüchern zum Formatieren von Zeichenfolgen. Es hilft mir, das von mir verwendete Zeichenfolgenformat zu lesen und vorhandene Wörterbücher zu nutzen. Beispielsweise:

class MyClass:
    def __init__(self):
        self.title = 'Title'

a = MyClass()
print 'The title is %(title)s' % a.__dict__

path = '/path/to/a/file'
print 'You put your file here: %(path)s' % locals()

Ich kann jedoch die Python 3.x-Syntax nicht herausfinden, um dasselbe zu tun (oder ob dies überhaupt möglich ist). Ich möchte Folgendes tun

# Fails, KeyError 'latitude'
geopoint = {'latitude':41.123,'longitude':71.091}
print '{latitude} {longitude}'.format(geopoint)

# Succeeds
print '{latitude} {longitude}'.format(latitude=41.123,longitude=71.091)
Doran
quelle

Antworten:

15

Da die Frage spezifisch für Python 3 ist, wird hier die neue F-String-Syntax verwendet , die seit Python 3.6 verfügbar ist:

>>> geopoint = {'latitude':41.123,'longitude':71.091}
>>> print(f'{geopoint["latitude"]} {geopoint["longitude"]}')
41.123 71.091

Beachten Sie die äußeren einfachen Anführungszeichen und inneren doppelten Anführungszeichen (Sie können es auch umgekehrt machen).

Wyrmwood
quelle
Ich würde sagen, dass die Verwendung des F-Strings eher auf den Python3-Ansatz ausgerichtet ist.
Jonatas CD
2
Beachten Sie, dass F-Strings in Python 3.6 neu sind und nicht in 3.5.
Hugo
409

Ist das gut für dich

geopoint = {'latitude':41.123,'longitude':71.091}
print('{latitude} {longitude}'.format(**geopoint))
Cocoatomo
quelle
2
Versuchte dies und es funktionierte. Aber ich verstehe die Verwendung der 'Zeigernotation' nicht. Ich weiß, dass Python keine Zeiger verwendet. Ist dies ein Beispiel für kwargs?
Homunculus Reticulli
2
@HomunculusReticulli Dies ist ein Formatparameter (minimale Feldbreite), kein Zeiger auf einen Zeiger-C ++ - Stil. docs.python.org/release/2.4.4/lib/typesseq-strings.html
D.Rosado
29
Python 3.2 eingeführt format_map. Ähnlich wie str.format(**mapping), nur dass dies mappingdirekt verwendet und nicht in a kopiert wird dict. Dies ist nützlich, wenn es sich beispielsweise mappingum eine Diktat-Unterklasse handelt
Diapir
1
@eugene Was macht ** mit einem Python-Wörterbuch? Ich glaube nicht, dass es ein Objekt erstellt, weil print (** geopoint)
keinen
4
@NityeshAgarwal verbreitet das Wörterbuch mit den Namen = Wert-Paaren als einzelne Argumente, dh es print(**geopoint)ist dasselbe wie print(longitude=71.091, latitude=41.123). In vielen Sprachen wird es als Splat-Operator bezeichnet . In JavaScript heißt es Spread-Operator . In Python wird diesem Operator kein bestimmter Name zugewiesen.
Abhisekp
79

Verwenden Sie zum Entpacken eines Wörterbuchs in Schlüsselwortargumente **. Außerdem unterstützt die Formatierung im neuen Stil das Verweisen auf Attribute von Objekten und Elementen von Zuordnungen:

'{0[latitude]} {0[longitude]}'.format(geopoint)
'The title is {0.title}s'.format(a) # the a from your first example

quelle
2
Ich finde diese Antwort besser, da das Hinzufügen des Positionsindex für den Platzhalter den Code expliziter und benutzerfreundlicher macht. Besonders wenn man so etwas hat:'{0[latitude]} {1[latitude]} {0[longitude]} {1[longitude]}'.format(geopoint0, geopoint1)
Løiten
1
Dies ist nützlich, wenn Sie eine verwenden defaultdictund nicht alle Schlüssel haben
Whymarrh
65

Da Python 3.0 und 3.1 EOL'ed sind und niemand sie verwendet, können und sollten Sie verwenden str.format_map(mapping) (Python 3.2+) verwenden:

Ähnlich wie str.format(**mapping), außer dass das Mapping direkt verwendet und nicht in a kopiert wirddict . Dies ist nützlich, wenn das Mapping beispielsweise eine dictUnterklasse ist.

Dies bedeutet, dass Sie zum Beispiel a verwenden können defaultdict , das einen Standardwert für fehlende Schlüssel festlegt (und zurückgibt):

>>> from collections import defaultdict
>>> vals = defaultdict(lambda: '<unset>', {'bar': 'baz'})
>>> 'foo is {foo} and bar is {bar}'.format_map(vals)
'foo is <unset> and bar is baz'

Auch wenn das bereitgestellte Mapping a ist dict eine Unterklasse und keine Unterklasse ist, wäre dies wahrscheinlich immer noch etwas schneller.

Der Unterschied ist jedoch nicht groß

>>> d = dict(foo='x', bar='y', baz='z')

dann

>>> 'foo is {foo}, bar is {bar} and baz is {baz}'.format_map(d)

ist etwa 10 ns (2%) schneller als

>>> 'foo is {foo}, bar is {bar} and baz is {baz}'.format(**d)

auf meinem Python 3.4.3. Der Unterschied wäre wahrscheinlich größer, wenn mehr Schlüssel im Wörterbuch enthalten sind, und


Beachten Sie, dass die Formatsprache jedoch viel flexibler ist. sie können indiziert Ausdrücke enthalten, Attributzugriffe und so weiter, so dass Sie können ein ganzes Objekt zu formatieren, oder 2 von ihnen:

>>> p1 = {'latitude':41.123,'longitude':71.091}
>>> p2 = {'latitude':56.456,'longitude':23.456}
>>> '{0[latitude]} {0[longitude]} - {1[latitude]} {1[longitude]}'.format(p1, p2)
'41.123 71.091 - 56.456 23.456'

Ab 3.6 können Sie auch die interpolierten Zeichenfolgen verwenden:

>>> f'lat:{p1["latitude"]} lng:{p1["longitude"]}'
'lat:41.123 lng:71.091'

Sie müssen nur daran denken, die anderen Anführungszeichen in den verschachtelten Anführungszeichen zu verwenden. Ein weiterer Vorteil dieses Ansatzes ist, dass er viel schneller ist als das Aufrufen einer Formatierungsmethode.

Antti Haapala
quelle
Schön, gibt es Leistungsverbesserungen gegenüber format? (Da es nicht in ein Diktat kopiert wird)
Bhargav Rao
2
@ BhargavRao nicht viel, 2%: D
Antti Haapala
@ BhargavRao Wenn Sie nach Leistung suchen, verwenden Sie diese '%(latitude)s %(longitude)s'%geopoint;)
Tcll
20
print("{latitude} {longitude}".format(**geopoint))
S.Lott
quelle
6

Die Python 2-Syntax funktioniert auch in Python 3:

>>> class MyClass:
...     def __init__(self):
...         self.title = 'Title'
... 
>>> a = MyClass()
>>> print('The title is %(title)s' % a.__dict__)
The title is Title
>>> 
>>> path = '/path/to/a/file'
>>> print('You put your file here: %(path)s' % locals())
You put your file here: /path/to/a/file
Lennart Regebro
quelle
Außerdem ist es merklich performanter als f""oder "".format();)
Tcll
2
geopoint = {'latitude':41.123,'longitude':71.091}

# working examples.
print(f'{geopoint["latitude"]} {geopoint["longitude"]}') # from above answer
print('{geopoint[latitude]} {geopoint[longitude]}'.format(geopoint=geopoint)) # alternate for format method  (including dict name in string).
print('%(latitude)s %(longitude)s'%geopoint) # thanks @tcll
Scheich Abdul Wahid
quelle
1
du hast eins verpasst;) print('%(latitude)s %(longitude)s'%geopoint)das ist auch deutlich schneller als das andere 2
Tcll
@tcll Eigentlich wollte ich die Beispiele, in denen ich den Wörterbuchnamen in der Zeichenfolge verwenden kann. So etwas in der Art'%(geopoint["latitude"])s %(geopoint["longitude"])s'%{"geopoint":geopoint}
Sheikh Abdul Wahid
1

Die meisten Antworten formatierten nur die Werte des Diktats.

Wenn Sie den Schlüssel auch in die Zeichenfolge formatieren möchten, können Sie dict.items () verwenden :

geopoint = {'latitude':41.123,'longitude':71.091}
print("{} {}".format(*geopoint.items()))

Ausgabe:

("Breitengrad", 41,123) ("Längengrad", 71,091)

Wenn Sie arbitry formatieren möchten, dh die Schlüsselwerte wie Tupel nicht anzeigen:

from functools import reduce
print("{} is {} and {} is {}".format(*reduce((lambda x, y: x + y), [list(item) for item in geopoint.items()])))

Ausgabe:

Breitengrad ist 41.123 und Längengrad ist 71.091

victortv
quelle
Beachten Sie, dass es eine Chance gibt, dass 'Längengrad' vor 'Breitengrad' von kommt geopoint.items();)
Tcll