Python - пишуть () проти писань () та об'єднаних рядків


124

Тому я вивчаю Python. Я проходжу уроки і зіткнувся з проблемою, коли мені довелося конденсувати велику кількість target.write()в єдину write(), маючи "\n"між кожною вхідною змінною користувача (об'єкт write()).

Я придумав:

nl = "\n"
lines = line1, nl, line2, nl, line3, nl
textdoc.writelines(lines)

Якщо я спробую зробити:

textdoc.write(lines)

Я отримую помилку. Але якщо я набираю:

textdoc.write(line1 + "\n" + line2 + ....)

Тоді це прекрасно працює. Чому я не можу використовувати рядок для нового рядка в, write()але я можу використовувати його в writelines()?

Python 2.7 Коли я шукав google, то більшість ресурсів, які я виявив, були над головою, я все ще непрофесійні люди.


linesне є рядком у вашому прикладі. Це кортеж, що складається з шести струн.
Бахсау

Відповіді:


147
  • writelines очікує ітерабельний рядок
  • write очікує одного рядка.

line1 + "\n" + line2об'єднує ці рядки разом в один рядок, перш ніж передати його write.

Зауважте, що якщо у вас багато рядків, ви можете скористатися "\n".join(list_of_lines).


50
Більш конкретно, writelinesрозраховує на повтор. Ви можете використовувати список, кортеж або генератор.
Марк Рансом

Дякую за відповідь, сер. Я припускаю по імені (list_of_lines), що мені слід скласти список рядків і перейти потім у .join (список)?
AbeLinkon

9
Чому слід використовувати writeзамість, writelinesякщо у вас багато ліній? Лінійки можуть бути ефективнішими, оскільки не потрібно створювати тимчасовий об'єднаний рядок, просто повторюючи рядки.
Буке

@ HBy2Py: як раз навпаки: stackoverflow.com/a/6165711/281545
Mr_and_Mrs_D

1
Один рядок також є ітерабельним у Python
natbusa

123

Чому я не в змозі використовувати рядок для нового рядка в write (), але я можу використовувати його в написанні ()?

Ідея така: якщо ви хочете написати один рядок, ви можете це зробити write(). Якщо у вас є послідовність рядків, ви можете записати їх усі, використовуючи writelines().

write(arg)очікує рядок як аргумент і записує його у файл. Якщо ви надасте список рядків, це створить виняток (до речі, покажіть нам помилки!).

writelines(arg)очікує ітерабельний аргумент (ітерабельним об'єктом може бути кортеж, список, рядок або ітератор у найбільш загальному сенсі). Очікується, що кожен елемент, що міститься в ітераторі, буде рядком. Набір струн - це те, що ви надали, щоб все працювало.

Характер рядків (ив) не має значення для обох функцій, тобто вони просто записують у файл все, що ви їм надаєте. Цікава частина полягає в тому, що writelines()вони не додають символи нового рядка самостійно, тому назва методу насправді може бути досить заплутаною. Він насправді веде себе як уявний метод, який називається write_all_of_these_strings(sequence).

Далі йде ідіоматичний спосіб у Python написати список рядків у файл, зберігаючи кожну рядок у своєму рядку:

lines = ['line1', 'line2']
with open('filename.txt', 'w') as f:
    f.write('\n'.join(lines))

Це допоможе закрити файл для вас. Конструкція '\n'.join(lines)об'єднує (з'єднує) рядки у списку linesта використовує символ '\ n' як клей. Це більш ефективно, ніж використання +оператора.

Починаючи з тієї ж linesпослідовності, закінчуючи тим самим висновком, але використовуючи writelines():

lines = ['line1', 'line2']
with open('filename.txt', 'w') as f:
    f.writelines("%s\n" % l for l in lines)

Це використовує генераторний вираз і динамічно створює рядки, що закінчуються новим рядком. writelines()повторює цю послідовність рядків і записує кожен елемент.

Редагування: Ще один момент, про який слід знати:

write()і readlines()існували раніше, коли writelines()було введено. writelines()пізніше було представлено як аналог readlines(), щоб можна було легко записати вміст файлу, який щойно читали через readlines():

outfile.writelines(infile.readlines())

Дійсно, це головна причина, чому writelinesвона має таку заплутану назву. Також сьогодні ми дуже не хочемо більше використовувати цей метод. readlines()зчитує весь файл в пам'ять вашого апарату, перш ніж writelines()починає записувати дані. Перш за все, це може втратити час. Чому б не почати писати частини даних під час читання інших частин? Але, найголовніше, такий підхід може бути дуже трудомістким. У крайньому випадку, коли вхідний файл більший за об'єм пам'яті вашої машини, такий підхід навіть не працює. Рішення цієї проблеми полягає лише у використанні ітераторів. Робочий приклад:

with open('inputfile') as infile:
    with open('outputfile') as outfile:
        for line in infile:
            outfile.write(line)

Це читає вхідний файл рядок. Як тільки прочитається один рядок, цей рядок записується у вихідний файл. Схематично кажучи, у пам'яті завжди є лише один рядок (порівняно з усім вмістом файлу, який знаходиться в пам'яті, у випадку підходу readlines / pisceedines).


5
@AbeLinkon: Я б не підтримав цей висновок. write()і writelines()в основному еквівалентні і їх використання також є питанням особистого смаку. Однак важливо зазначити, що для надзвичайно довгого списку рядків (так званих lines) писати менш ефективно, f.write('\n'.join(lines))ніж for l in line: f.write('%s\n' % l). У першому випадку перед пам’яткою створюється абсолютно нова і дуже довга струна. У другому випадку дані записуються детально.
Доктор Ян-Філіп Геркк

3
f.write ('\ n'.join (рядки)) не додав останній nl, коли я запускав його.
Jiminion

5
Звичайно, ви б цього не зробили, outf.writelines(inf.readlines())а скоріше outf.writelines(inf). Функція, яку ми більше не хочемо використовувати, readlines()не є writelines().
moooeeeep

2
@moooeeeep: хоча функціональність / реалізація нічого не буває writelines(), його семантика, як було пояснено, менш ідеальна. Ось чому я його ніколи не використовував. І я ніколи цього не сумував.
Доктор Ян-Філіп Геркк

2
@AbeLinkon - можливо, вам варто прийняти цю відповідь, це явно краще, ніж той, який ви спочатку прийняли
Пітер М. - виступає за Моніку

-4

якщо ви просто хочете зберегти та завантажити список, спробуйте Pickle

Економія соління:

with open("yourFile","wb")as file:
 pickle.dump(YourList,file)

і завантаження:

with open("yourFile","rb")as file:
 YourList=pickle.load(file)

-5

Власне, я думаю, що проблема полягає в тому, що ваші змінні "рядки" погані. Ви визначили рядки як кортеж, але я вважаю, що для запису () потрібен рядок. Все, що вам потрібно змінити, - це коми в плюси (+).

nl = "\n"
lines = line1+nl+line2+nl+line3+nl
textdoc.writelines(lines)

повинен працювати.


-5

Вправа 16 з книги Зеда Шоу? Ви можете використовувати символи втечі наступним чином:

paragraph1 = "%s \n %s \n %s \n" % (line1, line2, line3)
target.write(paragraph1)
target.close()

Дуже слабке рішення. Якщо ви хочете , щоб об'єднати кілька рядків таким чином, ви повинні зробити це в такий спосіб : " \n ".join((line1, line2, line3)).
Bachsau
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.