Zauważ, że codecs.open()jest to przestarzałe w 3.x, ponieważ open()zyskuje encodingargument.
Ignacio Vazquez-Abrams
Jest też trzeci sposób (przynajmniej w Pythonie 2.x): `f = plik (nazwa pliku) '
Adam Parkin
1
@ IgnacioVazquez-Abrams Czy istnieje link, który codecs.open()jest przestarzały? Nie sądzę, żeby to było w dokumentach Python3
varela
1
@varela: wspomniana strona dokumentacji Pythona mówi: „wbudowany open () i powiązany moduł io to zalecane podejście do pracy z zakodowanymi plikami tekstowymi”
Luciano Ramalho
Odpowiedzi:
83
Od Pythona 2.6, dobrą praktyką jest używanie io.open(), które również przyjmuje encodingargument, tak jak teraz przestarzały codecs.open(). W Pythonie 3 io.openjest aliasem dla open()wbudowanego. io.open()Działa więc w Pythonie 2.6 i wszystkich późniejszych wersjach, w tym w Pythonie 3.4. Zobacz dokumentację: http://docs.python.org/3.4/library/io.html
A teraz, jeśli chodzi o pierwotne pytanie: podczas czytania tekstu (w tym „zwykłego tekstu”, HTML, XML i JSON) w Pythonie 2 należy zawsze używać io.open()z jawnym kodowaniem lub open()z jawnym kodowaniem w Pythonie 3. Czyniąc to, uzyskasz poprawny wynik zdekodować Unicode lub otrzymać błąd od razu, co znacznie ułatwia debugowanie.
Czysty ASCII „zwykły tekst” to mit z odległej przeszłości. Prawidłowy tekst w języku angielskim używa cudzysłowów, myślników, punktorów, € (znaki euro), a nawet dierezy (¨). Nie bądź naiwny! (I nie zapominajmy o wzorcu projektowym elewacji!)
Ponieważ czysty ASCII nie jest prawdziwą opcją, open()bez jawnego kodowania jest przydatny tylko do odczytu plików binarnych .
@ForeverWintr Odpowiedź jest tam dość jasna: użyj io.open()dla tekstu i open()tylko dla plików binarnych. Wniosek jest taki, że codecs.open()wcale nie jest to preferowane.
Bdoserror
2
@Bdoserror, Jest odpowiedź tam wyraźnie, ale to nie jest odpowiedź na pytanie, które zostało zadane. Pytanie dotyczyło różnicy między i , a konkretnie, kiedy to drugie jest lepsze od pierwszego. Odpowiedź, która nawet nie wspomina, nie może odpowiedzieć na to pytanie. opencodecs.opencodecs.open
ForeverWintr
3
@ForeverWintr Jeśli OP zapytał źle pytanie (tj. Z założeniem, że codecs.open()było poprawne w użyciu), nie ma „poprawnej” odpowiedzi na temat tego, kiedy go użyć. Odpowiedź brzmi: użyj io.open()zamiast tego. To tak, jakby zapytać „kiedy powinienem wbić gwóźdź w ścianę kluczem?”. Prawidłowa odpowiedź to „użyj młotka”.
Bdoserror
20
Osobiście zawsze używam, codecs.openchyba że istnieje jasno określona potrzeba użycia open**. Powodem jest to, że tyle razy zostałem ugryziony przez wejście utf-8, które wkradło się do moich programów. „Och, po prostu wiem, że to zawsze będzie ascii” to założenie, które często się łamie.
Zakładanie „utf-8” jako domyślnego kodowania wydaje się być bezpieczniejszym domyślnym wyborem z mojego doświadczenia, ponieważ ASCII można traktować jako UTF-8, ale odwrotność nie jest prawdą. A w tych przypadkach, kiedy naprawdę wiem, że dane wejściowe to ASCII, nadal robię to, codecs.openponieważ mocno wierzę w „wyraźne jest lepsze niż ukryte” .
** - w Pythonie 2.x, ponieważ openzastępuje komentarz do stanów pytania w Pythonie 3codecs.open
to, czego tak naprawdę nie rozumiem, to dlaczego openczasami radzę sobie bardzo dobrze ze
znakami niełacińskimi
To ma dla mnie sens. io.opennie pobiera parametru kodowania z tego, co widzę w Pythonie 2.7.5
radtek
1
@radtek, masz rację, że jest to nieudokumentowane; jednak (przynajmniej w 2.7.12) io.openakceptuje encodingi newlineparametry i interpretuje je tak, jak robi to Python 3. W przeciwieństwie do tego codecs.open, plik otwarty za pomocą io.openpodniesie się TypeError: write() argument 1 must be unicode, not strnawet w Pythonie 2.7, jeśli spróbujesz do niego napisać str( bytes). Plik otwarty za pomocą codecs.openzamiast tego będzie próbował niejawnej konwersji do unicode, co często prowadzi do mylących plików UnicodeDecodeErrors.
jochietoch
9
W Pythonie 2 istnieją ciągi znaków Unicode i bajty. Jeśli używasz tylko bytestringów, możesz czytać / zapisywać do pliku otwartego w open()porządku. W końcu łańcuchy to tylko bajty.
Problem pojawia się, gdy, powiedzmy, masz ciąg znaków Unicode i wykonujesz następujące czynności:
>>> example = u'Μου αρέσει Ελληνικά'>>> open('sample.txt', 'w').write(example)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
Więc tutaj oczywiście albo jawnie kodujesz swój ciąg znaków Unicode w utf-8, albo codecs.openrobisz to za siebie w sposób przejrzysty.
Jeśli używasz tylko bajtestów, nie ma problemów:
>>> example = 'Μου αρέσει Ελληνικά'>>> open('sample.txt', 'w').write(example)
>>>
Wiąże się to bardziej niż to, ponieważ kiedy łączysz Unicode i testujesz łańcuch z +operatorem, otrzymujesz ciąg znaków Unicode. Łatwo się przez to ugryźć.
Również codecs.opennie lubi bytestrings ze znakami spoza ASCII są przekazywane w:
codecs.open('test', 'w', encoding='utf-8').write('Μου αρέσει')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/codecs.py", line 691, in write
return self.writer.write(data)
File "/usr/lib/python2.7/codecs.py", line 351, in write
data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xce in position 0: ordinal not in range(128)
Porada dotycząca ciągów znaków wejściowych / wyjściowych jest zwykle „konwertowana do formatu Unicode tak wcześnie, jak to możliwe i z powrotem do bajtestów tak późno, jak to możliwe”. Użycie codecs.openpozwala bardzo łatwo zrobić to drugie.
Po prostu uważaj, aby nadawać mu ciągi znaków Unicode, a nie bajty, które mogą zawierać znaki spoza ASCII.
Czy możesz wyjaśnić swój drugi przykład? Wygląda na to, że jest identyczny z pierwszym przykładem, więc dlaczego wynik miałby być inny?
Chris Johnson,
Zwróć uwagę na użycie u''w pierwszym przykładzie. Oznacza to, że utworzyłem ciąg znaków Unicode, a nie bajt. Na tym polega różnica między tymi dwoma przykładami. W drugim przykładzie tworzę bajtestowanie i zapisanie jednego z nich do pliku jest w porządku. Ciąg znaków Unicode nie jest w porządku, jeśli używasz znaków spoza ASCII.
Żuchwa79
7
Gdy potrzebujesz otworzyć plik, który ma określone kodowanie, użyjesz codecsmodułu.
codecs.openPrzypuszczam, że to pozostałość po Python 2czasach, kiedy wbudowany otwarty miał znacznie prostszy interfejs i mniej możliwości. W Pythonie 2 openfunkcja wbudowana nie pobiera argumentu kodowania, więc jeśli chcesz użyć czegoś innego niż tryb binarny lub domyślne kodowanie, powinno zostać użyte codecs.open.
W Python 2.6roku moduł io przyszedł z pomocą, aby nieco uprościć sprawę. Według oficjalnej dokumentacji
New in version 2.6.
The io module provides the Python interfaces to stream handling.
Under Python 2.x, this is proposed as an alternative to the
built-in file object, but in Python 3.x it is the default
interface to access files and streams.
Powiedziawszy to, jedyne zastosowanie, jakie przychodzi mi do głowy codecs.openw obecnym scenariuszu, to kompatybilność wsteczna. We wszystkich innych scenariuszach (chyba że używasz Pythona <2.6) lepiej jest używać io.open. Również w Python 3.xio.openjest to samo cobuilt-in open
Uwaga:
Istnieje również różnica składniowa między codecs.openi io.open.
Nie tylko codecs.openi io.openróżnią się składnią, ale zwracają obiekty różnego typu. codecs.openDziała również zawsze z plikami w trybie binarnym.
wombatonfire
4
Jeśli chcesz załadować plik binarny, użyj
f = io.open(filename, 'b').
Aby otworzyć plik tekstowy, zawsze używaj f = io.open(filename, encoding='utf-8')z jawnym kodowaniem.
W Pythonie 3 jednak opennie to samo, co io.openi może być stosowany zamiast.
Uwaga:codecs.open planuje się stać przestarzałe i zastąpione przez io.openpo wprowadzeniu w Pythonie 2.6 . Użyłbym go tylko wtedy, gdy kod musi być zgodny z wcześniejszymi wersjami Pythona. Aby uzyskać więcej informacji na temat kodeków i Unicode w Pythonie, zobacz Unicode HOWTO .
1. Dlaczego nie mogę otworzyć pliku w trybie binarnym za pomocą io.openlub codecs.open? 2. codecs.opennie jest jeszcze przestarzała, przeczytaj dyskusję na stronie, do której masz łącze.
wombatonfire
Słuszne uwagi! 1. Możesz użyć jednego z nich, ale ponownie odradzałbym codecs.open, chyba że używasz Pythona 2.5 lub starszego. 2. Zaktualizowałem swoją odpowiedź, aby odzwierciedlić, że wycofanie nie nastąpiło natychmiast, ale raczej w przyszłości.
wihlke
3
Kiedy pracujesz z plikami tekstowymi i potrzebujesz przezroczystego kodowania i dekodowania do obiektów Unicode.
codecs.open()
jest to przestarzałe w 3.x, ponieważopen()
zyskujeencoding
argument.codecs.open()
jest przestarzały? Nie sądzę, żeby to było w dokumentach Python3Odpowiedzi:
Od Pythona 2.6, dobrą praktyką jest używanie
io.open()
, które również przyjmujeencoding
argument, tak jak teraz przestarzałycodecs.open()
. W Pythonie 3io.open
jest aliasem dlaopen()
wbudowanego.io.open()
Działa więc w Pythonie 2.6 i wszystkich późniejszych wersjach, w tym w Pythonie 3.4. Zobacz dokumentację: http://docs.python.org/3.4/library/io.htmlA teraz, jeśli chodzi o pierwotne pytanie: podczas czytania tekstu (w tym „zwykłego tekstu”, HTML, XML i JSON) w Pythonie 2 należy zawsze używać
io.open()
z jawnym kodowaniem lubopen()
z jawnym kodowaniem w Pythonie 3. Czyniąc to, uzyskasz poprawny wynik zdekodować Unicode lub otrzymać błąd od razu, co znacznie ułatwia debugowanie.Czysty ASCII „zwykły tekst” to mit z odległej przeszłości. Prawidłowy tekst w języku angielskim używa cudzysłowów, myślników, punktorów, € (znaki euro), a nawet dierezy (¨). Nie bądź naiwny! (I nie zapominajmy o wzorcu projektowym elewacji!)
Ponieważ czysty ASCII nie jest prawdziwą opcją,
open()
bez jawnego kodowania jest przydatny tylko do odczytu plików binarnych .źródło
io.open()
dla tekstu iopen()
tylko dla plików binarnych. Wniosek jest taki, żecodecs.open()
wcale nie jest to preferowane.open
codecs.open
codecs.open
codecs.open()
było poprawne w użyciu), nie ma „poprawnej” odpowiedzi na temat tego, kiedy go użyć. Odpowiedź brzmi: użyjio.open()
zamiast tego. To tak, jakby zapytać „kiedy powinienem wbić gwóźdź w ścianę kluczem?”. Prawidłowa odpowiedź to „użyj młotka”.Osobiście zawsze używam,
codecs.open
chyba że istnieje jasno określona potrzeba użyciaopen
**. Powodem jest to, że tyle razy zostałem ugryziony przez wejście utf-8, które wkradło się do moich programów. „Och, po prostu wiem, że to zawsze będzie ascii” to założenie, które często się łamie.Zakładanie „utf-8” jako domyślnego kodowania wydaje się być bezpieczniejszym domyślnym wyborem z mojego doświadczenia, ponieważ ASCII można traktować jako UTF-8, ale odwrotność nie jest prawdą. A w tych przypadkach, kiedy naprawdę wiem, że dane wejściowe to ASCII, nadal robię to,
codecs.open
ponieważ mocno wierzę w „wyraźne jest lepsze niż ukryte” .** - w Pythonie 2.x, ponieważ
open
zastępuje komentarz do stanów pytania w Pythonie 3codecs.open
źródło
open
czasami radzę sobie bardzo dobrze zeio.open
nie pobiera parametru kodowania z tego, co widzę w Pythonie 2.7.5io.open
akceptujeencoding
inewline
parametry i interpretuje je tak, jak robi to Python 3. W przeciwieństwie do tegocodecs.open
, plik otwarty za pomocąio.open
podniesie sięTypeError: write() argument 1 must be unicode, not str
nawet w Pythonie 2.7, jeśli spróbujesz do niego napisaćstr
(bytes
). Plik otwarty za pomocącodecs.open
zamiast tego będzie próbował niejawnej konwersji dounicode
, co często prowadzi do mylących plikówUnicodeDecodeError
s.W Pythonie 2 istnieją ciągi znaków Unicode i bajty. Jeśli używasz tylko bytestringów, możesz czytać / zapisywać do pliku otwartego w
open()
porządku. W końcu łańcuchy to tylko bajty.Problem pojawia się, gdy, powiedzmy, masz ciąg znaków Unicode i wykonujesz następujące czynności:
>>> example = u'Μου αρέσει Ελληνικά' >>> open('sample.txt', 'w').write(example) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
Więc tutaj oczywiście albo jawnie kodujesz swój ciąg znaków Unicode w utf-8, albo
codecs.open
robisz to za siebie w sposób przejrzysty.Jeśli używasz tylko bajtestów, nie ma problemów:
>>> example = 'Μου αρέσει Ελληνικά' >>> open('sample.txt', 'w').write(example) >>>
Wiąże się to bardziej niż to, ponieważ kiedy łączysz Unicode i testujesz łańcuch z
+
operatorem, otrzymujesz ciąg znaków Unicode. Łatwo się przez to ugryźć.Również
codecs.open
nie lubi bytestrings ze znakami spoza ASCII są przekazywane w:codecs.open('test', 'w', encoding='utf-8').write('Μου αρέσει') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.7/codecs.py", line 691, in write return self.writer.write(data) File "/usr/lib/python2.7/codecs.py", line 351, in write data, consumed = self.encode(object, self.errors) UnicodeDecodeError: 'ascii' codec can't decode byte 0xce in position 0: ordinal not in range(128)
Porada dotycząca ciągów znaków wejściowych / wyjściowych jest zwykle „konwertowana do formatu Unicode tak wcześnie, jak to możliwe i z powrotem do bajtestów tak późno, jak to możliwe”. Użycie
codecs.open
pozwala bardzo łatwo zrobić to drugie.Po prostu uważaj, aby nadawać mu ciągi znaków Unicode, a nie bajty, które mogą zawierać znaki spoza ASCII.
źródło
u''
w pierwszym przykładzie. Oznacza to, że utworzyłem ciąg znaków Unicode, a nie bajt. Na tym polega różnica między tymi dwoma przykładami. W drugim przykładzie tworzę bajtestowanie i zapisanie jednego z nich do pliku jest w porządku. Ciąg znaków Unicode nie jest w porządku, jeśli używasz znaków spoza ASCII.Gdy potrzebujesz otworzyć plik, który ma określone kodowanie, użyjesz
codecs
modułu.źródło
codecs.open
Przypuszczam, że to pozostałość poPython 2
czasach, kiedy wbudowany otwarty miał znacznie prostszy interfejs i mniej możliwości. W Pythonie 2open
funkcja wbudowana nie pobiera argumentu kodowania, więc jeśli chcesz użyć czegoś innego niż tryb binarny lub domyślne kodowanie, powinno zostać użyte codecs.open.W
Python 2.6
roku moduł io przyszedł z pomocą, aby nieco uprościć sprawę. Według oficjalnej dokumentacjiNew in version 2.6. The io module provides the Python interfaces to stream handling. Under Python 2.x, this is proposed as an alternative to the built-in file object, but in Python 3.x it is the default interface to access files and streams.
Powiedziawszy to, jedyne zastosowanie, jakie przychodzi mi do głowy
codecs.open
w obecnym scenariuszu, to kompatybilność wsteczna. We wszystkich innych scenariuszach (chyba że używasz Pythona <2.6) lepiej jest używaćio.open
. Również wPython 3.x
io.open
jest to samo cobuilt-in open
Uwaga:
Istnieje również różnica składniowa między
codecs.open
iio.open
.codecs.open
:open(filename, mode='rb', encoding=None, errors='strict', buffering=1)
io.open
:open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
źródło
codecs.open
iio.open
różnią się składnią, ale zwracają obiekty różnego typu.codecs.open
Działa również zawsze z plikami w trybie binarnym.Jeśli chcesz załadować plik binarny, użyj
f = io.open(filename, 'b')
.Aby otworzyć plik tekstowy, zawsze używaj
f = io.open(filename, encoding='utf-8')
z jawnym kodowaniem.W Pythonie 3 jednak
open
nie to samo, coio.open
i może być stosowany zamiast.źródło
io.open
lubcodecs.open
? 2.codecs.open
nie jest jeszcze przestarzała, przeczytaj dyskusję na stronie, do której masz łącze.Kiedy pracujesz z plikami tekstowymi i potrzebujesz przezroczystego kodowania i dekodowania do obiektów Unicode.
źródło
Miałem okazję otworzyć plik .asm i go przetworzyć.
#https://docs.python.org/3/library/codecs.html#codecs.ignore_errors #https://docs.python.org/3/library/codecs.html#codecs.Codec.encode
with codecs.open(file, encoding='cp1252', errors ='replace') as file:
Bez większego problemu jestem w stanie odczytać cały plik, jakieś sugestie?
źródło