Ich verwende Vorlagenzeichenfolgen, um einige Dateien zu generieren, und ich liebe die Prägnanz der neuen F-Zeichenfolgen für diesen Zweck, um meinen vorherigen Vorlagencode von so etwas zu reduzieren:
template_a = "The current name is {name}"
names = ["foo", "bar"]
for name in names:
print (template_a.format(**locals()))
Jetzt kann ich dies tun und Variablen direkt ersetzen:
names = ["foo", "bar"]
for name in names:
print (f"The current name is {name}")
Manchmal ist es jedoch sinnvoll, die Vorlage an einer anderen Stelle zu definieren - weiter oben im Code oder aus einer Datei oder etwas anderem importiert. Dies bedeutet, dass die Vorlage eine statische Zeichenfolge mit Formatierungs-Tags ist. Es müsste etwas mit der Zeichenfolge passieren, um den Interpreter anzuweisen, die Zeichenfolge als neue F-Zeichenfolge zu interpretieren, aber ich weiß nicht, ob es so etwas gibt.
Gibt es eine Möglichkeit, eine Zeichenfolge einzubringen und als F-Zeichenfolge zu interpretieren, um die Verwendung des .format(**locals())
Aufrufs zu vermeiden ?
Idealerweise möchte ich in der Lage sein, so zu codieren ... (wo magic_fstring_function
kommt der Teil ins Spiel, den ich nicht verstehe):
template_a = f"The current name is {name}"
# OR [Ideal2] template_a = magic_fstring_function(open('template.txt').read())
names = ["foo", "bar"]
for name in names:
print (template_a)
... mit dieser gewünschten Ausgabe (ohne die Datei zweimal zu lesen):
The current name is foo
The current name is bar
... aber die tatsächliche Ausgabe, die ich bekomme, ist:
The current name is {name}
The current name is {name}
f
String kann man das nicht machen . Einef
Zeichenfolge besteht nicht aus Daten, und es handelt sich sicherlich nicht um eine Zeichenfolge. Es ist Code. (Überprüfen Sie dies mit demdis
Modul.) Wenn Sie möchten, dass Code zu einem späteren Zeitpunkt ausgewertet wird, verwenden Sie eine Funktion..format(**locals())
, obwohl kosmetisch schöner. Bis PEP-501 implementiert ist.Antworten:
Hier ist ein komplettes "Ideal 2".
Es ist kein F-String - es werden nicht einmal F-Strings verwendet - aber es funktioniert wie gewünscht. Syntax genau wie angegeben. Keine Sicherheitskopfschmerzen, da wir nicht verwenden
eval()
.Es verwendet eine kleine Klasse und implementiert,
__str__
die automatisch von print aufgerufen wird. Um dem begrenzten Umfang der Klasse zu entgehen, verwenden wir dasinspect
Modul, um einen Frame nach oben zu springen und die Variablen anzuzeigen, auf die der Aufrufer Zugriff hat.quelle
template = "The beginning of the name is {name[:4]}"
(->TypeError: string indices must be integers
)str.format
. Früher dachte ich, F-Strings seien nur syntaktischer Zucker für so etwas,str.format(**locals(), **globals())
aber offensichtlich habe ich mich geirrt.inspect
ist eine rote Fahne.__slots__
hier für die reduzierte Speichernutzung?Ja, genau deshalb haben wir Literale mit Ersatzfeldern und
.format
können die Felder jederzeit ersetzen, indem wir sie aufrufenformat
.Das ist das Präfix
f/F
. Sie könnten es in eine Funktion einbinden und die Auswertung während der Anrufzeit verschieben, aber das verursacht natürlich zusätzlichen Aufwand:Welches druckt aus:
fühlt sich aber falsch an und wird durch die Tatsache eingeschränkt, dass Sie nur einen Blick auf den globalen Namespace in Ihren Ersetzungen werfen können. Der Versuch, es in einer Situation zu verwenden, in der lokale Namen erforderlich sind, schlägt kläglich fehl, es sei denn, es wird als Argument an die Zeichenfolge übergeben (was den Punkt völlig übertrifft).
Anders als eine Funktion (einschließlich Einschränkungen), nein, könnte genauso gut bei bleiben
.format
.quelle
Eine prägnante Möglichkeit, eine Zeichenfolge als F-Zeichenfolge (mit ihren vollen Funktionen) auszuwerten, besteht in der Verwendung der folgenden Funktion:
Dann können Sie tun:
Und im Gegensatz zu vielen anderen Lösungsvorschlägen können Sie auch Folgendes tun:
quelle
name
ist global. f-Strings sollten bei der Auswertung zurückgestellt werden, aber die Klasse FString muss eine Liste von Verweisen auf die Argumente mit Gültigkeitsbereich erstellen, indem sie die lokalen und globalen Aufrufer des Aufrufers betrachtet ... und dann den String auswertet, wenn er verwendet wird.eval()
wird generell von der Verwendung von abgeraten.Eine F-Zeichenfolge ist einfach eine präzisere Methode zum Erstellen einer formatierten Zeichenfolge, die
.format(**names)
durch ersetzt wirdf
. Wenn Sie nicht möchten, dass eine Zeichenfolge sofort auf diese Weise ausgewertet wird, machen Sie sie nicht zu einer F-Zeichenfolge. Speichern Sie es als gewöhnliches Zeichenfolgenliteral und rufen Sieformat
es später auf, wenn Sie die Interpolation wie bisher ausführen möchten.Natürlich gibt es eine Alternative mit
eval
.template.txt
::Code:
Aber dann haben Sie es geschafft , zu tun ist , zu ersetzen
str.format
miteval
, das ist sicherlich nicht wert. Verwenden Sie bei einemformat
Aufruf einfach weiterhin normale Zeichenfolgen .quelle
The current name is {name}
in dietemplate.txt
Datei schreiben und dannprint(template_a.format(name=name))
(oder.format(**locals())
) verwenden. Der Code ist ungefähr 10 Zeichen länger, führt jedoch aufgrund von Sicherheitsproblemen nicht zu möglichen Problemeneval
.eval
es uns erlaubt,f'{name}'
die Auswertungname
bis zum gewünschten Zeitpunkt zu schreiben und zu verzögern , ist es minderwertig, einfach eine reguläre Vorlagenzeichenfolge zu erstellen und diese dann aufzurufenformat
, wie es das OP bereits getan hat..format
es sich nicht um einen F-String handelt, der Sie bei folgenden Kommentaren unterstützen kann :DNA = "TATTCGCGGAAAATATTTTGA"; fragment = f"{DNA[2:8]}"; failed_fragment = "{DNA[2:8]}".format(**locals())
. Der Versuch,failed_fragment
Ergebnisse zu erstellen, führt zuTypeError: string indices must be integers
.Die Verwendung von .format ist keine korrekte Antwort auf diese Frage. Python-F-Strings unterscheiden sich stark von str.format () -Vorlagen. Sie können Code oder andere teure Operationen enthalten - daher ist eine Verschiebung erforderlich.
Hier ist ein Beispiel für einen verzögerten Logger. Dies verwendet die normale Präambel von logging.getLogger, fügt dann aber neue Funktionen hinzu, die den f-String nur interpretieren, wenn die Protokollstufe korrekt ist.
Dies hat den Vorteil, dass Sie Folgendes tun können:
log.fdebug("{obj.dump()}")
.... ohne das Objekt zu sichern, es sei denn, das Debuggen ist aktiviert.IMHO: Dies hätte die Standardoperation von F-Strings sein sollen, aber jetzt ist es zu spät . Die Auswertung von F-Strings kann massive und unbeabsichtigte Nebenwirkungen haben, und wenn dies auf verzögerte Weise geschieht, ändert sich die Programmausführung.
Um F-Strings richtig zu verschieben, würde Python eine Möglichkeit benötigen, das Verhalten explizit zu ändern. Vielleicht den Buchstaben 'g' verwenden? ;)
quelle
%timeit log.finfo(f"{bar=}") 91.9 µs ± 7.45 µs per loop %timeit log.info(f"{bar=}") 56.2 µs ± 630 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) log.setLevel(logging.CRITICAL) %timeit log.finfo("{bar=}") 575 ns ± 2.9 ns per loop %timeit log.info(f"{bar=}") 480 ns ± 9.37 ns per loop %timeit log.finfo("") 571 ns ± 2.66 ns per loop %timeit log.info(f"") 380 ns ± 0.92 ns per loop %timeit log.info("") 367 ns ± 1.65 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Was Sie wollen, scheint als Python- Erweiterung betrachtet zu werden .
In der verknüpften Diskussion scheint Folgendes eine vernünftige Problemumgehung zu sein, für die keine Verwendung erforderlich ist
eval()
:Ausgabe:
quelle
Inspiriert von der Antwort von Kadee kann das Folgende verwendet werden, um eine verzögerte F-String-Klasse zu definieren.
Das ist genau das, wonach die Frage gestellt wurde
quelle
Oder verwenden Sie keine F-Strings, sondern formatieren Sie einfach:
In Version ohne Namen:
quelle
fun = "{DNA[2:8]}".format; DNA = "TATTCGCGGAAAATATTTTGA"; fun(DNA=DNA)
. ->TypeError: string indices must be integers
Ein Vorschlag, der F-Strings verwendet. Führen Sie Ihre Bewertung auf der logischen Ebene durch, auf der das Templating stattfindet, und übergeben Sie es als Generator. Sie können es an jedem beliebigen Punkt mit F-Strings abwickeln
quelle
Wie wäre es mit:
quelle