Formatieren Sie Zeichenfolgen und benannte Argumente in Python

72

Fall 1:

"{arg1} {arg2}".format(10, 20)

Es wird geben, KeyError: 'arg1'weil ich die genannten Argumente nicht übergeben habe.

Fall 2:

"{arg1} {arg2}".format(arg1=10, arg2=20)

Jetzt wird es richtig funktionieren, weil ich die genannten Argumente übergeben habe. Und es druckt'10 20'

Fall 3:

Und wenn ich einen falschen Namen übergebe, wird dies angezeigt KeyError: 'arg1'

"{arg1} {arg2}".format(wrong=10, arg2=20)

Aber,

Fall 4:

Wenn ich die genannten Argumente in falscher Reihenfolge übergebe

"{arg1} {arg2}".format(arg2=10, arg1=20)

Es klappt...

und es druckt '20 10'

Meine Frage ist, warum es funktioniert und wie benannte Argumente in diesem Fall verwendet werden.

bkmagnetron
quelle
Ich denke, sie dienen nur der Lesbarkeit.
Svineet
11
Weil es eher nach Namen als nach Position sucht ... was bedeutet Ihrer Meinung nach benannte Argumente?
aaa90210
2
Es sieht so aus, als hätten Sie arg2 einfach in arg1 umbenannt und umgekehrt. Mit anderen Worten, arg1 ist jetzt 20 statt 10, weshalb Sie die erste Zahl in Ihrem Zeichenfolgendruck 20 statt 10 sehen. Um den gewünschten Test durchzuführen, müssen Sie einfach die Argumente UND ihre Werte an die neue Position in verschieben das format () ruft auf und es würde sich so verhalten, wie Sie es erwarten. Hier ist nichts ungewöhnlich.
Brad P.

Antworten:

123

Benannte Ersetzungsfelder (die {...}Teile in einer Formatzeichenfolge ) stimmen mit Schlüsselwortargumenten der .format()Methode und nicht mit Positionsargumenten überein .

Schlüsselwortargumente sind wie Schlüssel in einem Wörterbuch. Reihenfolge spielt keine Rolle, da sie mit einem Namen abgeglichen werden .

Wenn Sie mit Positionsargumenten übereinstimmen möchten, verwenden Sie Zahlen:

"{0} {1}".format(10, 20)

In Python 2.7 und höher können Sie die Zahlen weglassen. Die {}Ersatzfelder werden dann in der Reihenfolge ihres Auftretens in der Formatierungszeichenfolge automatisch nummeriert:

"{} {}".format(10, 20) 

Die Formatierungszeichenfolge kann sowohl mit Positions- als auch mit Schlüsselwortargumenten übereinstimmen und Argumente mehrfach verwenden:

"{1} {ham} {0} {foo} {1}".format(10, 20, foo='bar', ham='spam')

Zitiert aus der Format - String - Spezifikation :

Der Feldname selbst beginnt mit einem Argumentnamen , der entweder eine Zahl oder ein Schlüsselwort ist . Wenn es sich um eine Zahl handelt, bezieht sie sich auf ein Positionsargument, und wenn es sich um ein Schlüsselwort handelt, bezieht sie sich auf ein benanntes Schlüsselwortargument.

Hervorhebung von mir.

Wenn Sie eine große Formatierungszeichenfolge erstellen, ist es häufig viel besser lesbar und wartbar, benannte Ersatzfelder zu verwenden, sodass Sie die Argumente nicht ständig zählen und herausfinden müssen, welches Argument wohin in die resultierende Zeichenfolge fließt.

Sie können auch die **keywordsaufrufende Syntax verwenden, um ein vorhandenes Wörterbuch auf ein Format anzuwenden, sodass Sie eine CSV-Datei einfach in eine formatierte Ausgabe umwandeln können:

import csv

fields = ('category', 'code', 'price', 'description', 'link', 'picture', 'plans')
table_row = '''\
    <tr>
      <td><img src="{picture}"></td>
      <td><a href="{link}">{description}</a> ({price:.2f})</td>
   </tr>
'''

with open(filename, 'rb') as infile:
    reader = csv.DictReader(infile, fieldnames=fields, delimiter='\t')
    for row in reader:
        row['price'] = float(row['price'])  # needed to make `.2f` formatting work
        print table_row.format(**row)

Hier picture, link, descriptionund pricesind alle Schlüssel im rowWörterbuch, und es ist viel einfacher zu sehen , was passiert , wenn ich die Anwendung rowauf die Formatierung Zeichenfolge.

Martijn Pieters
quelle
3
Es ist nicht nur besser lesbar, sondern auch sehr nützlich, wenn Sie mit natürlichen Sprachen und "Internationalisierung" (i18n) arbeiten, bei denen manchmal bestimmte Teile einer formatierten Nachricht in unterschiedlichen Reihenfolgen in verschiedenen Sprachen ausgegeben werden sollen.
Torek
1
@torek: Ich wollte nicht einmal auf die verschiedenen Ordnungen in der Vorlage eingehen. Der Punkt ist, dass jeder Slot auf ein bestimmtes Argument verweist. Sie können die Positionsargumente auch in der Vorlage in einer anderen Reihenfolge einfügen.
Martijn Pieters
4

Zusätzliche Vorteile sind

  • Sie müssen sich nicht um die Reihenfolge der Argumente kümmern . Sie werden an der richtigen Stelle in den Zeichenfolgen platziert, wie durch die Namen im Formatierer angegeben.
  • Sie können dasselbe Argument zweimal in eine Zeichenfolge einfügen , ohne das Argument wiederholen zu müssen. ZB "{foo} {foo}".format(foo="bar")gibt 'Bar Bar'

Beachten Sie, dass Sie zusätzliche Argumente angeben können, ohne Fehler zu verursachen. All dies ist besonders nützlich, wenn

  • Sie ändern den String-Formatierer später mit weniger Änderungen und damit geringerer Fehlermöglichkeit . Wenn es keine neuen benannten Argumente enthält, funktioniert die Formatierungsfunktion weiterhin, ohne die Argumente zu ändern und die Argumente dort zu platzieren, wo Sie sie im Formatierer angeben.
  • Sie können mehrere Formatierungszeichenfolgen verwenden, die eine Reihe von Argumenten gemeinsam nutzen . In diesem Fall könnten Sie beispielsweise ein Wörterbuch mit allen Argumenten haben und diese dann im Formatierer auswählen, wenn Sie sie benötigen.

Z.B:

>d = {"foo":"bar", "test":"case", "dead":"beef"}
>print("I need foo ({foo}) and dead ({dead})".format(**d))
>print("I need test ({test}) and foo ({foo}) and then test again ({test})".format(**d))
I need foo (bar) and dead (beef)
I need test (case) and foo (bar) and then test again (case)
Koen G.
quelle
Das letzte Beispiel ist einer der praktischsten Ansätze zur Codierung von Vorlagenzeichenfolgen in Python, die ich je gesehen habe. Insbesondere war mir nicht bewusst, dass es möglich ist, ein Wörterbuchargument an eine Stelle zu übergeben, formatan der nicht alle Schlüssel tatsächlich in der Formatzeichenfolge erscheinen. Vielen Dank für den Hinweis!
Starturtle