sprintf comme fonctionnalité en Python

131

Je voudrais créer un tampon de chaîne pour faire beaucoup de traitement, formater et enfin écrire le tampon dans un fichier texte en utilisant une sprintffonctionnalité de style C en Python. En raison des instructions conditionnelles, je ne peux pas les écrire directement dans le fichier.

par exemple pseudo code:

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

Donc, dans le fichier de sortie, nous avons ce type d'o / p:

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

Edit, pour clarifier ma question:
buf est un gros tampon contient toutes ces chaînes qui ont été formatées à l'aide de sprintf. En suivant vos exemples, bufne contiendra que les valeurs actuelles, pas les plus anciennes. par exemple, le premier dans bufj'ai écrit A= something ,B= somethingplus tard a C= somethingété ajouté dans le même buf, mais dans vos réponses Python bufne contient que la dernière valeur, ce que je ne veux pas - je veux bufavoir tout ce que printfj'ai fait depuis le début, comme dans C.

printemps
la source
1
Ce n'est pas comme ça que sprintf () fonctionne en C. (Il écrit le contenu au début buf, pas à la fin.) Il serait probablement préférable d'utiliser un tableau de chaînes, puis de les joindre avant d'écrire dans le fichier.
yam655
@dividebyzero N'est-ce pas trivial en Python car c'est un langage de programmation général? Par exemple, voir la solution de Michael J. Barber (publiée après votre commentaire). def sprintf(buf, fmt, *args): ...
jdk1.0
@ jdk1.0 Je ne sais pas ce que je voulais dire, j'étais jeune et naïf programmeur Python ... Cette question est en fait bizarre parce que cette chose de réutilisation de tampon n'est pas si simple, vous auriez besoin d'incrémenter un pointeur avec la sortie de chaque appel de sprintf, et ce genre de chose n'est pas quelque chose dont vous devriez vous soucier si vous utilisez Python. Quoi qu'il en soit, je suis content d'être passé à Scala et maintenant Julia!
dividebyzero

Réponses:

170

Python a un %opérateur pour cela.

>>> 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

Consultez cette référence pour tous les spécificateurs de format pris en charge.

Vous pouvez également utiliser format:

>>> print "This is the {}th tome of {}".format(5, "knowledge")
This is the 5th tome of knowledge
Alexei Sholik
la source
40

Si je comprends bien votre question, le format () est ce que vous recherchez, avec son mini-langage .

Exemple idiot pour python 2.7 et plus:

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

Pour les versions antérieures de python: (testé avec 2.6.2)

>>> print "{0} ...\r\n {1}!".format("Hello", "world")
Hello ...
 world!
Nicolas Lefebvre
la source
4
Vous devriez probablement noter que cette version ne fonctionne qu'en Python 3. En Python 2.6, par exemple, vous devez faire:"{0} ...\r\n {1}!".format("Hello", "world")
Mark Longair
1
Modifier ma réponse pour l'inclure; ne pas que cela fonctionne aussi pour python 2.7 cependant!
Nicolas Lefebvre
20

Je ne suis pas tout à fait certain de comprendre votre objectif, mais vous pouvez utiliser une StringIOinstance comme tampon:

>>> 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

Contrairement à sprintf, vous passez simplement une chaîne à buf.write, en la formatant avec l' %opérateur ou la formatméthode des chaînes.

Vous pouvez bien sûr définir une fonction pour obtenir l' sprintfinterface que vous espérez:

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

qui serait utilisé comme ceci:

>>> 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
Michael J. Barber
la source
2
+1 pour m'avoir montré comment utiliser * args avec l'opérateur de formatage de chaîne (%).
Curtis Yallop
pour Python3 utiliser à la io.StringIO()place
Wolf
11

Vous pouvez utiliser le formatage de chaîne:

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

Mais cela est supprimé dans Python 3, vous devez utiliser "str.format ()":

>>> 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'
utdemir
la source
4
Faux, il n'est pas supprimé dans Python 3. Python 3.0 a dit qu'il serait obsolète dans 3.1 mais je pense que cela ne s'est jamais produit. L'utilisation format()peut être préférable mais le %formatage existe toujours. (Voir mail.python.org/pipermail/python-dev/2009-September/092399.html pour une partie des raisons pour lesquelles il n'était pas obsolète)
Duncan
1
@Duncan; merci, je ne le savais pas. J'ai lu quelque part qu'il était obsolète et je n'ai jamais réessayé :).
utdemir
7

Pour insérer dans une très longue chaîne, il est agréable d'utiliser des noms pour les différents arguments, au lieu d'espérer qu'ils sont aux bonnes positions. Cela facilite également le remplacement de plusieurs récurrences.

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

Tiré d' exemples de format , où toutes les autres Formatréponses liées sont également affichées.

Jost
la source
3

C'est probablement la traduction la plus proche de votre code C en code Python.

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()

L' %opérateur en Python fait presque exactement la même chose que C de sprintf. Vous pouvez également imprimer la chaîne directement dans un fichier. S'il y a beaucoup de ces stringlets formatés en chaîne, il peut être judicieux d'utiliser un StringIOobjet pour accélérer le temps de traitement.

Alors au lieu de faire +=, faites ceci:

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()
YH Wong
la source
3

Si vous voulez quelque chose comme la fonction d'impression python3 mais à une chaîne:

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"

ou sans le '\n'à la fin:

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}"
Michael
la source
1

Quelque chose comme...

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

Hello John
bmatovu
la source
Cela imprime une chaîne sur la console, pas dans une chaîne, ce que l'OP voulait.
Teemu Leisti
Cela a également imprimé% s à l'écran, ce qui n'était pas prévu; mais j'aime le fait que je peux ajouter plusieurs variables avec une virgule.
b01
0

Deux approches consistent à écrire dans un tampon de chaîne ou à écrire des lignes dans une liste et à les joindre plus tard. Je pense que l' StringIOapproche est plus pythonique, mais n'a pas fonctionné avant Python 2.6.

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())

Vous pouvez également les utiliser sans ContextMananger( s = StringIO()). Actuellement, j'utilise une classe de gestionnaire de contexte avec une printfonction. Ce fragment peut être utile pour pouvoir insérer des exigences de débogage ou de pagination étranges:

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=':')
Charles Merriam
la source