Sprintf-ähnliche Funktionalität in Python


131

Ich möchte einen Zeichenfolgenpuffer erstellen, um viel zu verarbeiten, zu formatieren und schließlich den Puffer in eine Textdatei zu schreiben, wobei eine C-ähnliche sprintfFunktionalität in Python verwendet wird. Aufgrund von bedingten Anweisungen kann ich sie nicht direkt in die Datei schreiben.

zB Pseudocode:

sprintf(buf,"A = %d\n , B= %s\n",A,B)
/* some processing */
sprint(buf,"C=%d\n",c)
....
...
fprintf(file,buf)

In der Ausgabedatei haben wir also diese Art von O / P:

A= foo B= bar
C= ded
etc...

Bearbeiten, um meine Frage zu klären:
buf Ist ein großer Puffer enthält alle diese Zeichenfolgen, die mit sprintf formatiert wurden. Wenn Sie sich Ihre Beispiele ansehen, bufwerden nur aktuelle Werte enthalten, keine älteren. zB wurde zuerst in, das bufich A= something ,B= somethingspäter schrieb, C= somethingdasselbe angehängt buf, aber in Ihren Python-Antworten bufist nur der letzte Wert enthalten, den ich nicht möchte - ich möchte bufalle printfs haben, die ich von Anfang an getan habe, wie in C.


1
So funktioniert sprintf () in C nicht. (Es schreibt den Inhalt am Anfang bufund nicht am Ende.) Es ist wahrscheinlich am besten, ein Array von Zeichenfolgen zu verwenden und sie dann zusammenzufügen, bevor Sie in die Datei schreiben.
Yam655

@dividebyzero Ist dies in Python nicht trivial, da es sich um eine allgemeine Programmiersprache handelt? Siehe zum Beispiel die Lösung von Michael J. Barber (veröffentlicht nach Ihrem Kommentar). def sprintf(buf, fmt, *args): ...
JDK1.0

@ jdk1.0 Ich weiß nicht, was ich meinte, ich war ein junger und naiver Python-Programmierer ... Diese Frage ist eigentlich komisch, weil diese Sache mit der Pufferwiederverwendung nicht so einfach ist. Sie müssten einen Zeiger mit der Ausgabe von inkrementieren Bei jedem Sprintf-Aufruf sollten Sie sich keine Sorgen machen, wenn Sie Python ausführen. Wie auch immer, ich bin froh, dass ich zu Scala und jetzt zu Julia gewechselt bin!
Dividebyzero

Antworten:


169

Python hat dafür einen %Operator.

>>> a = 5
>>> b = "hello"
>>> buf = "A = %d\n , B = %s\n" % (a, b)
>>> print buf
A = 5
 , B = hello

>>> c = 10
>>> buf = "C = %d\n" % c
>>> print buf
C = 10

In dieser Referenz finden Sie alle unterstützten Formatspezifizierer.

Sie könnten auch verwenden format:

>>> print "This is the {}th tome of {}".format(5, "knowledge")
This is the 5th tome of knowledge

40

Wenn ich Ihre Frage richtig verstehe, ist format () genau das, wonach Sie suchen, zusammen mit seiner Minisprache .

Dummes Beispiel für Python 2.7 und höher:

>>> print "{} ...\r\n {}!".format("Hello", "world")
Hello ...
 world!

Für frühere Python-Versionen: (getestet mit 2.6.2)

>>> print "{0} ...\r\n {1}!".format("Hello", "world")
Hello ...
 world!

4
Sie sollten wahrscheinlich beachten, dass diese Version nur in Python 3 funktioniert. In Python 2.6 müssen Sie beispielsweise "{0} ...\r\n {1}!".format("Hello", "world")
Folgendes

1
Bearbeiten meiner Antwort, um das einzuschließen; nicht, dass es auch für Python 2.7 funktioniert!
Nicolas Lefebvre

20

Ich bin nicht ganz sicher, ob ich Ihr Ziel verstehe, aber Sie können eine StringIOInstanz als Puffer verwenden:

>>> import StringIO 
>>> buf = StringIO.StringIO()
>>> buf.write("A = %d, B = %s\n" % (3, "bar"))
>>> buf.write("C=%d\n" % 5)
>>> print(buf.getvalue())
A = 3, B = bar
C=5

Im Gegensatz dazu übergeben sprintfSie einfach eine Zeichenfolge an buf.writeund formatieren sie mit dem %Operator oder der formatMethode der Zeichenfolgen.

Sie können natürlich eine Funktion definieren, um die sprintfgewünschte Schnittstelle zu erhalten :

def sprintf(buf, fmt, *args):
    buf.write(fmt % args)

welches so verwendet werden würde:

>>> buf = StringIO.StringIO()
>>> sprintf(buf, "A = %d, B = %s\n", 3, "foo")
>>> sprintf(buf, "C = %d\n", 5)
>>> print(buf.getvalue())
A = 3, B = foo
C = 5

2
+1, um mir zu zeigen, wie man * args mit dem String-Formatierungsoperator (%) verwendet.
Curtis Yallop

für Python3 io.StringIO()stattdessen verwenden
Wolf


11

Sie können die Zeichenfolgenformatierung verwenden:

>>> a=42
>>> b="bar"
>>> "The number is %d and the word is %s" % (a,b)
'The number is 42 and the word is bar'

Dies wird jedoch in Python 3 entfernt. Sie sollten "str.format ()" verwenden:

>>> a=42
>>> b="bar"
>>> "The number is {0} and the word is {1}".format(a,b)
'The number is 42 and the word is bar'

4
Falsch, es wird in Python 3 nicht entfernt. Python 3.0 sagte, dass es in 3.1 veraltet sein würde, aber ich glaube, dass dies nie passiert ist. Die Verwendung ist format()möglicherweise vorzuziehen, die %Formatierung ist jedoch weiterhin vorhanden. (Siehe mail.python.org/pipermail/python-dev/2009-September/092399.html für einige der Gründe, warum es nicht veraltet war)
Duncan

1
@ Duncan; Danke, das wusste ich nicht. Ich habe irgendwo gelesen, dass es veraltet ist und habe es nie wieder versucht :).
utdemir

7

Zum Einfügen in eine sehr lange Zeichenfolge ist es hilfreich, Namen für die verschiedenen Argumente zu verwenden, anstatt zu hoffen, dass sie sich an den richtigen Positionen befinden. Dies erleichtert auch das Ersetzen mehrerer Wiederholungen.

>>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W')
'Coordinates: 37.24N, -115.81W'

Entnommen aus Formatbeispielen , in denen auch alle anderen FormatAntworten angezeigt werden.


3

Dies ist wahrscheinlich die nächste Übersetzung von Ihrem C-Code in Python-Code.

A = 1
B = "hello"
buf = "A = %d\n , B= %s\n" % (A, B)

c = 2
buf += "C=%d\n" % c

f = open('output.txt', 'w')
print >> f, c
f.close()

Der %Operator in Python macht fast genau das Gleiche wie Cs sprintf. Sie können die Zeichenfolge auch direkt in eine Datei drucken. Wenn viele dieser String-formatierten Stringlets beteiligt sind, ist es möglicherweise ratsam, a zu verwendenStringIO Objekt zu verwenden, um die Verarbeitungszeit zu verkürzen.

Anstatt dies zu tun +=, tun Sie Folgendes:

import cStringIO
buf = cStringIO.StringIO()

...

print >> buf, "A = %d\n , B= %s\n" % (A, B)

...

print >> buf, "C=%d\n" % c

...

print >> f, buf.getvalue()

3

Wenn Sie etwas wie die Python3-Druckfunktion wollen, aber eine Zeichenfolge:

def sprint(*args, **kwargs):
    sio = io.StringIO()
    print(*args, **kwargs, file=sio)
    return sio.getvalue()
>>> x = sprint('abc', 10, ['one', 'two'], {'a': 1, 'b': 2}, {1, 2, 3})
>>> x
"abc 10 ['one', 'two'] {'a': 1, 'b': 2} {1, 2, 3}\n"

oder ohne das '\n'am Ende:

def sprint(*args, end='', **kwargs):
    sio = io.StringIO()
    print(*args, **kwargs, end=end, file=sio)
    return sio.getvalue()
>>> x = sprint('abc', 10, ['one', 'two'], {'a': 1, 'b': 2}, {1, 2, 3})
>>> x
"abc 10 ['one', 'two'] {'a': 1, 'b': 2} {1, 2, 3}"

1

Etwas wie...

greetings = 'Hello {name}'.format(name = 'John')

Hello John

Dadurch wird eine Zeichenfolge an die Konsole gedruckt, nicht an eine Zeichenfolge, wie es das OP wollte.
Teemu Leisti

Dies druckte auch% s auf den Bildschirm, was nicht erwartet wurde; aber ich mag es, dass ich mehrere Variablen mit einem Komma hinzufügen kann.
B01


0

Zwei Ansätze bestehen darin, in einen Zeichenfolgenpuffer zu schreiben oder Zeilen in eine Liste zu schreiben und sie später zu verbinden. Ich denke, der StringIOAnsatz ist eher pythonisch, hat aber vor Python 2.6 nicht funktioniert.

from io import StringIO

with StringIO() as s:
   print("Hello", file=s)
   print("Goodbye", file=s)
   # And later...
   with open('myfile', 'w') as f:
       f.write(s.getvalue())

Sie können diese auch ohne ContextMananger( s = StringIO()) verwenden. Derzeit verwende ich eine Kontextmanagerklasse mit einer printFunktion. Dieses Fragment kann nützlich sein, um Debugging- oder ungerade Paging-Anforderungen einfügen zu können:

class Report:
    ... usual init/enter/exit
    def print(self, *args, **kwargs):
        with StringIO() as s:
            print(*args, **kwargs, file=s)
            out = s.getvalue()
        ... stuff with out

with Report() as r:
   r.print(f"This is {datetime.date.today()}!", 'Yikes!', end=':')
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.