Python'da sprintf benzeri işlevsellik


131

sprintfPython'da C tarzı bir işlevsellik kullanarak çok sayıda işlem yapmak, biçimlendirmek ve son olarak tamponu bir metin dosyasına yazmak için bir dize tamponu oluşturmak istiyorum . Koşullu ifadeler nedeniyle bunları doğrudan dosyaya yazamıyorum.

örneğin sözde kod:

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

Yani çıktı dosyasında bu tür bir o / p var:

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

Düzenleyin, sorumu açıklığa kavuşturmak için:
buf sprintf kullanılarak biçimlendirilmiş tüm bu dizeleri içeren büyük bir arabellek var mı? Örneklerinize göre, bufeski değerleri değil, yalnızca mevcut değerleri içerecektir. mesela ilk bufben yazdım A= something ,B= somethingdaha sonra C= somethingaynı yer ekinde buf, ancak Python cevaplarında bufdeğil istediğim olan yalnızca son değer içerir - İstediğim bufhepsine sahip printfs ı gibi, başından beri yapmış C.


1
Sprintf () C'de bu şekilde çalışmaz (İçeriği başında yazar, sonunda yazmaz buf.) Muhtemelen en iyisi, bir dizi dizge kullanmak ve dosyaya yazmadan önce bunları bir araya getirmek.
yam655

@dividebyzero Genel bir programlama dili olduğu için Python'da bu önemsiz değil mi? Örneğin, Michael J. Barber'ın çözümüne bakın (yorumunuzdan sonra yayınlanmıştır). def sprintf(buf, fmt, *args): ...
jdk1.0

@ jdk1.0 Ne demek istediğimi bilmiyorum, genç ve saf bir Python programcısıydım ... Bu soru aslında garip çünkü bu arabelleği yeniden kullanma işi o kadar basit değil, bir göstericinin çıktısı ile her sprintf çağrısı ve bu tür şeyler Python yapıyorsanız endişelenmeniz gereken bir şey değildir. Her neyse, Scala'ya ve şimdi de Julia'ya geçtiğim için mutluyum!
dividebyzero

Yanıtlar:


170

Python'un bunun için bir %operatörü vardır .

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

Desteklenen tüm biçim belirleyicileri için bu referansa bakın .

Sen de kullanabilirsin format:

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

40

Sorunuzu doğru anladıysam, mini dili ile birlikte aradığınız format () olacaktır .

Python 2.7 ve üstü için saçma bir örnek:

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

Önceki python sürümleri için: (2.6.2 ile test edilmiştir)

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

4
Muhtemelen bu sürümün yalnızca Python 3'te çalıştığını not etmelisiniz. Örneğin Python 2.6'da şunları yapmanız gerekir:"{0} ...\r\n {1}!".format("Hello", "world")
Mark Longair

1
Cevabımı bunu içerecek şekilde düzenlemek; yine de python 2.7 için çalıştığını değil!
Nicolas Lefebvre

20

Hedefinizi anladığımdan tam olarak emin değilim, ancak bir StringIOörneği tampon olarak kullanabilirsiniz :

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

Bunun aksine sprintf, sadece bir dizeyi operatörle veya dizelerin yöntemiyle buf.writebiçimlendirerek iletirsiniz .%format

Elbette sprintf, umduğunuz arayüzü elde etmek için bir işlev tanımlayabilirsiniz :

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

bunun gibi kullanılacak:

>>> 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
* Args'i dize biçimlendirme operatörü (%) ile nasıl kullanacağımı gösteren +1.
Curtis Yallop

Python3 için io.StringIO()bunun yerine kullanın
Wolf


11

Dize biçimlendirmesini kullanabilirsiniz:

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

Ancak bu Python 3'te kaldırılmıştır, "str.format ()" kullanmalısınız:

>>> 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
Yanlış, Python 3'te kaldırılmadı. Python 3.0, 3.1'de kullanımdan kaldırılacağını söyledi ama ben bunun hiç olmadığına inanıyorum. Kullanmak format()tercih edilebilir, ancak %biçimlendirme hala mevcuttur. ( Neden kullanımdan kaldırılmadığına ilişkin bazı nedenler için mail.python.org/pipermail/python-dev/2009-September/092399.html adresine bakın )
Duncan

1
@Duncan; teşekkürler, bunu bilmiyordum. Kullanımdan kaldırıldığı bir yerde okudum ve bir daha asla denemedim :).
utdemir

7

Çok uzun bir dizgeye eklemek için, doğru konumda olduklarını ummak yerine farklı argümanlar için adlar kullanmak güzeldir. Bu aynı zamanda birden fazla yinelemenin değiştirilmesini de kolaylaştırır.

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

Alındığı Biçim örneklerle tüm diğer, Formatlı cevaplar da gösterilmiştir.


3

Bu muhtemelen C kodunuzdan Python koduna en yakın çeviridir.

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

%Python operatör C'ler neredeyse tamamen aynı şeyi yapar sprintf. Dizeyi doğrudan bir dosyaya da yazdırabilirsiniz. Bu dizge formatlı dizgelerden çok sayıda varsa, StringIOişlem süresini hızlandırmak için bir nesne kullanmak akıllıca olabilir .

Yani yapmak yerine şunu yapın +=:

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

Python3 yazdırma işlevi gibi bir şey istiyorsanız, ancak bir dizeye:

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"

veya '\n'sonunda olmadan :

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

Gibi bir şey...

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

Hello John

Bu, OP'nin istediği bir dizgeye değil konsola bir dize yazdırır.
Teemu Leisti

Bu, beklenmeyen bir şekilde ekrana% s yazdırdı; ancak virgülle birden çok değişken ekleyebilmeyi seviyorum.
b01


0

İki yaklaşım, bir dizge arabelleğine yazmak veya satırları bir listeye yazmak ve daha sonra birleştirmektir. StringIOYaklaşımın daha pitonik olduğunu düşünüyorum , ancak Python 2.6'dan önce işe yaramadı.

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

Bunları a ContextMananger( s = StringIO()) olmadan da kullanabilirsiniz . Şu anda, printişlevli bir bağlam yöneticisi sınıfı kullanıyorum . Bu parça, hata ayıklama veya tek sayfalama gereksinimleri eklemek için yararlı olabilir:

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=':')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.