Python - write () по сравнению с Writelines () и конкатенированными строками

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, большинство ресурсов, которые я находил, были выше моей головы, я все еще был неспециалистом.

AbeLinkon
источник
linesне является строкой в ​​вашем примере. Это кортеж, состоящий из шести строк.
Bachsau

Ответы:

147
  • writelines ожидает итерацию строк
  • write ожидает одну строку.

line1 + "\n" + line2объединяет эти строки в одну перед передачей в write.

Обратите внимание: если у вас много строк, вы можете использовать "\n".join(list_of_lines).

рБоп
источник
50
В частности, writelinesожидает итеративного. Вы можете использовать список, кортеж или генератор.
Марк Рэнсом,
Спасибо за ответ, сэр. По имени (list_of_lines) я предполагаю, что я должен составить список строк и перейти затем в .join (list)?
AbeLinkon
9
Почему вы должны использовать writeвместо этого, writelinesесли у вас много строк? Линии записи могли бы быть более эффективными, поскольку им не нужно создавать временную объединенную строку, просто повторяя строки.
Bouke
@ hBy2Py: с точностью до наоборот: stackoverflow.com/a/6165711/281545
Mr_and_Mrs_D
1
Отдельная строка также является итерируемой в Python
natbusa
123

Почему я не могу использовать строку для перевода строки в write (), но могу использовать ее в Writelines ()?

Идея заключается в следующем: если вы хотите написать одну строку, вы можете сделать это с помощью 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)

Это считывает входной файл построчно. Как только одна строка прочитана, эта строка записывается в выходной файл. Схематично говоря, всегда есть только одна строка в памяти (по сравнению со всем содержимым файла, находящимся в памяти в случае подхода строк чтения / записи).

Д-р Ян-Филип Герке
источник
5
@AbeLinkon: Я бы не поддержал этот вывод. write()и writelines()в основном эквивалентны, и их использование также является вопросом личного вкуса. Однако важно отметить, что для очень длинного списка строк (называемых lines) писать менее эффективно, f.write('\n'.join(lines))чем for l in line: f.write('%s\n' % l). В первом случае перед записью в памяти создается совершенно новая и очень длинная строка. Во втором случае данные записываются кусочно.
Д-р Ян-Филип Герке,
3
f.write ('\ n'.join (lines)) не добавлял последний 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

На самом деле, я думаю, проблема в том, что ваша переменная "lines" плохая. Вы определили строки как кортеж, но я считаю, что write () требует строки. Все что вам нужно поменять запятые на плюсы (+).

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

должно сработать.

Kevin
источник
-5

Упражнение 16 из книги Зеда Шоу? Вы можете использовать escape-символы следующим образом:

paragraph1 = "%s \n %s \n %s \n" % (line1, line2, line3)
target.write(paragraph1)
target.close()
Джеральд
источник
Очень слабое решение. Если вы хотите , чтобы объединить несколько строк таким образом, вы должны сделать это следующим образом : " \n ".join((line1, line2, line3)).
Bachsau