sprintf как функциональность в Python

131

Я хотел бы создать строковый буфер для большой обработки, форматирования и, наконец, записи буфера в текстовый файл, используя функциональность C-стиля sprintfв Python. Из-за условных операторов я не могу записать их прямо в файл.

например псевдокод:

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

Итак, в выходном файле у нас есть такой o / p:

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

Изменить, чтобы прояснить мой вопрос:
buf большой буфер содержит все эти строки, отформатированные с помощью sprintf. Если следовать вашим примерам, они bufбудут содержать только текущие значения, а не старые. например, первое, что bufя написал A= something ,B= somethingпозже, C= somethingбыло добавлено таким же образом buf, но в ваших ответах Python bufсодержится только последнее значение, которого я не хочу - я хочу bufиметь все, что printfя делал с самого начала, например, в C.

весна
источник
1
Это не то, как sprintf () работает в C. (он записывает содержимое в начало buf, а не в конец.) Вероятно, лучше всего было бы использовать массив строк, а затем объединить их вместе, прежде чем записывать в файл.
yam655 05
@dividebyzero Разве это не тривиально для Python, поскольку это общий язык программирования? Например, см . Решение Майкла Дж. Барбера (опубликовано после вашего комментария). def sprintf(buf, fmt, *args): ...
jdk1.0
@ jdk1.0 Я не знаю, что я имел в виду, я был молодым и наивным программистом на Python ... Этот вопрос на самом деле странный, потому что эта вещь с повторным использованием буфера не так проста, вам нужно было бы увеличить указатель с выходом каждый вызов sprintf, и это не то, о чем вам следует беспокоиться, если вы работаете на Python. В любом случае, я рада, что перешла на Scala, а теперь на Джулию!
divyzero

Ответы:

170

В Python есть %для этого оператор.

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

См. Этот справочник для всех поддерживаемых спецификаторов формата.

Вы также можете использовать format:

>>> print "This is the {}th tome of {}".format(5, "knowledge")
This is the 5th tome of knowledge
Алексей Шолик
источник
40

Если я правильно понял ваш вопрос, вы ищете format () вместе с его мини-языком .

Глупый пример для Python 2.7 и выше:

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

Для более ранних версий python: (проверено с 2.6.2)

>>> print "{0} ...\r\n {1}!".format("Hello", "world")
Hello ...
 world!
Николя Лефевр
источник
4
Вы, вероятно, должны отметить, что эта версия работает только в Python 3. Например, в Python 2.6 вам необходимо сделать:"{0} ...\r\n {1}!".format("Hello", "world")
Марк Лонгэр,
1
Редактирую свой ответ, чтобы включить это; не так ли, что это также работает для python 2.7!
Николя Лефевр
20

Я не совсем уверен, что понимаю вашу цель, но вы можете использовать StringIOэкземпляр в качестве буфера:

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

В отличие от этого sprintf, вы просто передаете строку buf.write, форматируя ее с помощью %оператора или formatметода строк.

Конечно, вы можете определить функцию для получения sprintfинтерфейса, на который вы надеетесь:

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

который можно было бы использовать так:

>>> 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 за то, что показал мне, как использовать * args с оператором форматирования строки (%).
Curtis Yallop
для Python3 используйте io.StringIO()вместо этого
Wolf
11

Вы можете использовать форматирование строк:

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

Но это удалено в Python 3, вы должны использовать "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
источник
4
Неправильно, он не удален в Python 3. Python 3.0 сказал, что он будет устаревшим в 3.1, но я считаю, что этого не произошло. Использование format()может быть предпочтительнее, но %форматирование все еще существует. (См. Mail.python.org/pipermail/python-dev/2009-September/092399.html, почему он не устарел)
Дункан
1
@Duncan; спасибо, я этого не знал. Я где-то читал, что он устарел, и больше не пробовал :).
utdemir
7

Чтобы вставить в очень длинную строку, лучше использовать имена для различных аргументов, вместо того, чтобы надеяться, что они находятся в правильных позициях. Это также упрощает замену нескольких повторов.

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

Взято из примеров формата , где Formatтакже показаны все другие ответы.

Jost
источник
3

Это, вероятно, самый близкий перевод вашего кода C в код 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()

%Оператор в Python делает почти то же самое , как C - х sprintf. Вы также можете напрямую распечатать строку в файл. Если задействовано много таких строковых форматированных строк, было бы целесообразно использовать StringIOобъект для ускорения времени обработки.

Поэтому вместо этого +=сделайте следующее:

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, но в строке:

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"

или без '\n'конца:

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

Что-то вроде...

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

Hello John
bmatovu
источник
Это выводит строку на консоль, а не на строку, чего хотел OP.
Teemu Leisti
Это также напечатало% s на экране, чего не ожидалось; но мне нравится, что я могу добавить несколько переменных через запятую.
b01
0

Два подхода: запись в строковый буфер или запись строк в список и последующее присоединение к ним. Я думаю, что этот StringIOподход более питонический, но он не работал до 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())

Вы также можете использовать их без ContextMananger( s = StringIO()). В настоящее время я использую класс диспетчера контекста с printфункцией. Этот фрагмент может быть полезен для вставки требований отладки или нечетного разбиения на страницы:

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=':')
Чарльз Мерриам
источник