fungsionalitas seperti sprintf di Python

131

Saya ingin membuat buffer string untuk melakukan banyak pemrosesan, memformat dan akhirnya menulis buffer dalam file teks menggunakan sprintffungsionalitas C-style di Python. Karena pernyataan kondisional, saya tidak dapat menulisnya langsung ke file.

mis. kode semu:

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

Jadi dalam file output kita memiliki o / p:

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

Edit, untuk memperjelas pertanyaan saya:
buf apakah buffer besar berisi semua string yang telah diformat menggunakan sprintf. Mengikuti contoh Anda, bufhanya akan berisi nilai saat ini, bukan nilai yang lebih lama. misalnya pertama di bufsaya tulis A= something ,B= somethingkemudian C= somethingditambahkan dalam yang sama buf, tetapi dalam jawaban Python Anda bufhanya berisi nilai terakhir, yang tidak saya inginkan - Saya ingin bufmemiliki semua yang printftelah saya lakukan sejak awal, seperti pada C.

musim semi
sumber
1
Itu bukan cara sprintf () bekerja di C. (Ini menulis konten di awal buf, bukan di akhir.) Mungkin akan lebih baik menggunakan array string, kemudian bergabung bersama-sama sebelum Anda menulis ke file.
yam655
@dividebyzero Apakah ini tidak sepele dalam Python karena merupakan bahasa pemrograman umum? Misalnya, lihat solusi Michael J. Barber (diposting setelah komentar Anda). def sprintf(buf, fmt, *args): ...
jdk1.0
@ jdk1.0 Saya tidak tahu apa yang saya maksud, saya masih muda dan programmer Python naif ... Pertanyaan ini sebenarnya aneh karena hal penggunaan kembali buffer ini tidak sesederhana itu, Anda harus menambah pointer dengan output dari setiap panggilan sprintf, dan hal semacam ini bukan sesuatu yang Anda harus khawatirkan jika Anda melakukan Python. Bagaimanapun, saya senang saya pindah ke Scala dan sekarang Julia!
dividebyzero

Jawaban:

169

Python memiliki %operator untuk ini.

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

Lihat referensi ini untuk semua penentu format yang didukung.

Anda juga bisa menggunakan format:

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

Jika saya memahami pertanyaan Anda dengan benar, format () adalah apa yang Anda cari, beserta bahasa mini-nya .

Contoh konyol untuk python 2.7 dan lebih tinggi:

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

Untuk versi python sebelumnya: (diuji dengan 2.6.2)

>>> print "{0} ...\r\n {1}!".format("Hello", "world")
Hello ...
 world!
Nicolas Lefebvre
sumber
4
Anda mungkin harus mencatat bahwa versi itu hanya berfungsi dalam Python 3. Dalam Python 2.6, misalnya, Anda perlu melakukan:"{0} ...\r\n {1}!".format("Hello", "world")
Mark Longair
1
Mengedit jawaban saya untuk memasukkan itu; jangan lakukan itu juga berfungsi untuk python 2.7!
Nicolas Lefebvre
20

Saya tidak sepenuhnya yakin bahwa saya memahami tujuan Anda, tetapi Anda dapat menggunakan StringIOcontoh sebagai penyangga:

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

Tidak seperti sprintf, Anda hanya meneruskan string buf.write, memformatnya dengan %operator atau formatmetode string.

Anda tentu saja dapat mendefinisikan fungsi untuk mendapatkan sprintfantarmuka yang Anda harapkan:

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

yang akan digunakan seperti ini:

>>> 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
sumber
2
+1 untuk menunjukkan kepada saya cara menggunakan * args dengan operator pemformatan string (%).
Curtis Yallop
untuk Python3 menggunakan io.StringIO()bukannya
Serigala
13

Gunakan operator pemformatan% :

buf = "A = %d\n , B= %s\n" % (a, b)
print >>f, buf
NPE
sumber
11

Anda dapat menggunakan pemformatan string:

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

Tapi ini dihapus di Python 3, Anda harus menggunakan "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
sumber
4
Salah, itu tidak dihapus dalam Python 3. Python 3.0 mengatakan itu akan ditinggalkan dalam 3.1 tapi saya percaya itu tidak pernah terjadi. Menggunakan format()mungkin lebih disukai tetapi %format masih ada. (Lihat mail.python.org/pipermail/python-dev/2009-September/092399.html untuk beberapa alasan mengapa itu tidak ditinggalkan)
Duncan
1
@Duncan; terima kasih, saya tidak tahu itu. Saya membaca suatu tempat itu usang dan tidak pernah mencoba lagi :).
utdemir
7

Untuk memasukkan ke dalam string yang sangat panjang, itu baik untuk menggunakan nama untuk argumen yang berbeda, daripada berharap mereka berada di posisi yang tepat. Ini juga membuatnya lebih mudah untuk mengganti beberapa perulangan.

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

Diambil dari Contoh format , di mana semua Formatjawaban terkait lainnya juga ditampilkan.

Jost
sumber
3

Ini mungkin terjemahan terdekat dari kode C Anda ke kode 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()

The %operator dalam Python tidak hampir persis sama dengan C sprintf. Anda juga dapat mencetak string ke file secara langsung. Jika ada banyak stringlets string berformat ini yang terlibat, mungkin bijaksana untuk menggunakan StringIOobjek untuk mempercepat waktu pemrosesan.

Jadi alih-alih melakukan +=, lakukan ini:

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

Jika Anda ingin sesuatu seperti fungsi cetak python3 tetapi ke string:

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"

atau tanpa '\n'di akhir:

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

Sesuatu seperti...

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

Hello John
bmatovu
sumber
Ini mencetak string ke konsol, bukan ke string, itulah yang diinginkan OP.
Teemu Leisti
Ini juga mencetak% s ke layar, yang tidak diharapkan; tapi saya suka saya bisa menambahkan beberapa variabel dengan koma.
B01
0

Dua pendekatan adalah menulis ke buffer string atau menulis baris ke daftar dan bergabung nanti. Saya pikir StringIOpendekatannya lebih pythonic, tetapi tidak berhasil sebelum 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())

Anda juga dapat menggunakan ini tanpa ContextMananger( s = StringIO()). Saat ini, saya menggunakan kelas manajer konteks dengan printfungsi. Fragmen ini mungkin berguna untuk dapat memasukkan persyaratan debugging atau paging aneh:

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
sumber