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

@dividebyzero Це не тривіально в Python, оскільки це загальна мова програмування? Наприклад, дивіться рішення Майкла Дж. Барбера (розміщено після Вашого коментаря). def sprintf(buf, fmt, *args): ...
jdk1.0

@ jdk1.0 Я не знаю, що я мав на увазі, я був молодим і наївним програмістом Python ... Це питання насправді дивно, тому що ця проблема повторного використання буфера не така проста, вам потрібно буде наростити покажчик з виходом кожен дзвінок sprintf, і подібні речі - це не те, про що ви повинні турбуватися, якщо ви робите Python. У всякому разі, я радий, що я перейшов до Скали і зараз Юлії!
ділібайзеро

Відповіді:


169

У 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

Якщо я правильно розумію ваше запитання, формат () - це те, що ви шукаєте, а також його міні-мова .

Дурний приклад для 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")
Позначити Longair

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, щоб показати мені, як використовувати * аргументи з оператором форматування рядків (%).
Кертіс Яллоп

для Python3 використовуйте io.StringIO()натомість
Вовк


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'

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також показані всі відповіді, пов'язані з іншими .


3

Це, мабуть, найближчий переклад з вашого коду С на код 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

Це друкує рядок на консолі, а не на рядку, чого і хотів ОП.
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=':')
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.