Pytanie Python - write () versus writelines () i połączone ciągi


Więc uczę się Pythona. Przechodzę przez te lekcje i natknąłem się na problem, w którym musiałem skondensować bardzo wiele target.write() w singiel write(), mając jednocześnie "\n" między każdą zmienną wejściową użytkownika (obiekt write()).

Wymyśliłem:

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

Jeśli spróbuję:

textdoc.write(lines)

Wystąpił błąd. Ale jeśli napiszę:

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

Wtedy działa dobrze. Dlaczego nie mogę użyć ciągu znaków dla znaku nowej linii? write() ale mogę go użyć writelines()?

Python 2.7 Kiedy przeszukałem Google, większość zasobów, które znalazłem, było dla mnie ponad miarę, wciąż jestem świeckimi ludźmi.


76
2017-09-11 20:31


pochodzenie




Odpowiedzi:


writelines spodziewa się listy łańcuchów, podczas gdy write oczekuje pojedynczego ciągu znaków.

line1 + "\n" + line2 łączy te łańcuchy w jeden ciąg przed przekazaniem go write.

Zauważ, że jeśli masz wiele linii, możesz chcieć użyć "\n".join(list_of_lines).


93
2017-09-11 20:36



Dokładniej, writelines spodziewa się iteracji. Możesz użyć listy, krotki lub generatora. - Mark Ransom
Dziękuję za odpowiedź. Zakładam, że po nazwie (list_linii) powinienem sporządzić listę ciągów znaków i przekazać ją do .join (list)? - AbeLinkon
@AbeLinkon: Nie ma za co, a to się zgadza. - DGH
Dlaczego powinieneś używać write zamiast writelines jeśli masz wiele linii? Writryny mogą być lepiej wykonywane, ponieważ nie muszą tworzyć tymczasowego połączonego ciągu, tylko powtarzają się po liniach. - bouke
@MarkRansom. Myślę, że masz na myśli bardziej ogólnie :) - Mad Physicist


Dlaczego nie mogę użyć ciągu znaków dla znaku nowej linii w funkcji write (), ale mogę go użyć w Writelines ()?

Pomysł jest następujący: jeśli chcesz napisać pojedynczy ciąg, możesz to zrobić za pomocą write(). Jeśli masz ciąg ciągów, możesz je wszystkie zapisać za pomocą writelines().

write(arg) oczekuje ciągi jako argument i zapisuje ją do pliku. Jeśli podasz listę łańcuchów, spowoduje to zgłoszenie wyjątku (przy okazji, pokaż nam błędy!).

writelines(arg) spodziewa się, że będzie on iterowalny jako argument (obiekt iteracyjny może być krotką, listą, łańcuchem lub iteratorem w sensie najbardziej ogólnym). Każda pozycja zawarta w iteratorze ma być ciągiem. Dostarczono krotkę strun, więc wszystko działało.

Charakter ciągu (ów) nie ma znaczenia dla obu funkcji, tj. Po prostu zapisuje do pliku, cokolwiek mu podasz. Ciekawe jest to writelines() nie dodaje samodzielnie znaków nowego wiersza, więc nazwa metody może być dość myląca. Zachowuje się jak wyimaginowana metoda zwana write_all_of_these_strings(sequence).

Poniżej znajduje się idiomatyczny sposób w Pythonie, aby napisać listę ciągów do pliku, zachowując każdy ciąg we własnym wierszu:

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

To zajmie się zamknięciem pliku dla ciebie. Konstrukt '\n'.join(lines) konkatenuje (łączy) ciągi na liście lines i używa znaku "\ n" jako kleju. Jest bardziej wydajny niż użycie + operator.

Zaczynając od tego samego lines sekwencji, kończąc na tym samym wyjściu, ale używając writelines():

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

Wykorzystuje to wyrażenie generatora i dynamicznie tworzy łańcuchy zakończone znakiem nowej linii. writelines() iteruje po tej sekwencji ciągów i zapisuje każdy element.

Edytuj: Kolejny punkt, o którym powinieneś wiedzieć:

write() i readlines() istniały wcześniej writelines() został wprowadzony. writelines() został wprowadzony później jako odpowiednik readlines(), aby można było łatwo zapisać zawartość pliku, która została właśnie przeczytana readlines():

outfile.writelines(infile.readlines())

Naprawdę, to jest główny powód writelines ma takie mylące imię. Również dzisiaj nie chcemy już używać tej metody. readlines() wczytuje cały plik do pamięci urządzenia writelines() zaczyna zapisywać dane. Przede wszystkim może to marnować czas. Dlaczego nie zacząć pisać części danych podczas czytania innych części? Ale, co najważniejsze, takie podejście może być bardzo czasochłonne. W skrajnym scenariuszu, w którym plik wejściowy jest większy niż pamięć twojego komputera, takie podejście nawet nie zadziała. Rozwiązaniem tego problemu jest użycie tylko iteratorów. Przykład:

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

Czyta wiersz pliku wejściowego po linii. Zaraz po odczytaniu jednej linii ta linia zostanie zapisana w pliku wyjściowym. Mówi się schematycznie, zawsze w pamięci jest tylko jedna linia (w porównaniu do całej zawartości pliku w pamięci w przypadku podejścia readlines / writelines).


90
2017-09-11 20:40



@AbeLinkon: Nie poparłbym tego wniosku. write() i writelines() są w zasadzie ekwiwalentne, a ich użycie jest również kwestią osobistego gustu. Jednak ważne jest, aby pamiętać, że dla bardzo długiej listy ciągów (tzw lines) jest mniej wydajne w pisaniu f.write('\n'.join(lines)) niż for l in line: f.write('%s\n' % l). W pierwszym przypadku całkowicie nowy i bardzo długi ciąg jest tworzony w pamięci przed jego zapisaniem. W drugim przypadku dane są zapisywane jako częściowe. - Jan-Philip Gehrcke
f.write ('\ n'.join (linie)) nie dodaje ostatniego nl, kiedy go uruchomiłem. - Jiminion
Oczywiście nie zrobiłbyś tego outf.writelines(inf.readlines()) ale raczej outf.writelines(inf). Funkcja, której nie chcemy już używać, jest readlines() nie writelines(). - moooeeeep
@moooeeeep: podczas gdy nic nie jest nie tak z funkcjonalnością / implementacją writelines()jego semantyka jest, jak wyjaśniono, mniej niż idealna. Dlatego nigdy z niego nie korzystałem. I nigdy tego nie przeoczyłem. - Jan-Philip Gehrcke
@AbeLinkon - może powinieneś rozważyć zaakceptowanie tej odpowiedzi, jest ona zdecydowanie lepsza niż ta, którą pierwotnie zaakceptowałeś - P.M


W rzeczywistości myślę, że problem polega na tym, że twoje zmienne "linie" są złe. Zdefiniowałeś linie jako krotkę, ale uważam, że write () wymaga ciągu znaków. Wszystko, co musisz zmienić, to przecinki do plusów (+).

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

powinno działać.


-2
2017-09-17 22:18



Yikes. Dzięki Bogu .join() istnieje. - ZAD-Man


jeśli chcesz tylko zapisać i załadować listę, spróbuj Marynata

Oszczędzanie pikli:

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

i ładowanie:

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

-2
2018-03-11 15:29





Ćwiczenie 16 z książki Zeda Shawa? Możesz użyć znaków escape w następujący sposób:

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

-2
2018-02-06 07:30