Esistono due modi per aprire un file di testo in Python:
f = open(filename)
E
import codecs
f = codecs.open(filename, encoding="utf-8")
Quando è codecs.openpreferibile a open?
Esistono due modi per aprire un file di testo in Python:
f = open(filename)
E
import codecs
f = codecs.open(filename, encoding="utf-8")
Quando è codecs.openpreferibile a open?
codecs.open()obsoleto? Non credo che questo nel docs python3: docs.python.org/3.7/library/codecs.html
Risposte:
A partire da Python 2.6, una buona pratica è usare io.open(), che accetta anche un encodingargomento, come l'ormai obsoleto codecs.open(). In Python 3, io.openè un alias per il open()built-in. Quindi io.open()funziona in Python 2.6 e tutte le versioni successive, incluso Python 3.4. Vedi la documentazione: http://docs.python.org/3.4/library/io.html
Ora, per la domanda originale: quando leggi del testo (incluso "testo normale", HTML, XML e JSON) in Python 2 dovresti sempre usarlo io.open()con una codifica esplicita o open()con una codifica esplicita in Python 3. Ciò significa che ottieni correttamente decodificato Unicode, o ricevi subito un errore, rendendo molto più facile il debug.
Il puro "testo normale" ASCII è un mito del lontano passato. Il testo inglese corretto utilizza virgolette ricce, trattini emem, punti elenco, € (segni di euro) e persino dieresi (¨). Non essere ingenuo! (E non dimentichiamo il motivo di design della facciata!)
Poiché il puro ASCII non è un'opzione reale, open()senza una codifica esplicita è utile solo per leggere i file binari .
io.open()per il testo e open()solo per il binario. L'implicazione è che codecs.open()non è affatto preferito.
opene codecs.open, e in particolare quando il secondo è preferibile al primo. Una risposta che non è nemmeno menzionata codecs.opennon può rispondere a questa domanda.
codecs.open()fosse corretto da usare) allora non c'è una risposta "corretta" su quando usarla. La risposta è io.open()invece usare . È come se chiedessi "quando devo usare una chiave inglese per piantare un chiodo in un muro?". La risposta giusta è "usa un martello".
Personalmente, lo uso sempre acodecs.open meno che non ci sia una chiara esigenza identificata da usare open**. Il motivo è che ci sono state così tante volte in cui sono stato morso dall'input di utf-8 che si intrufola nei miei programmi. "Oh, so solo che sarà sempre ascii" tende ad essere un presupposto che viene infranto spesso.
Supponendo 'utf-8' come codifica predefinita tende ad essere una scelta predefinita più sicura nella mia esperienza, poiché ASCII può essere trattato come UTF-8, ma il contrario non è vero. E in quei casi in cui ho veramente non so che l'ingresso è ASCII, allora faccio ancora codecs.opencome io sono un convinto sostenitore "esplicito è meglio che implicito" .
** - in Python 2.x, come il commento sulla domanda afferma in Python 3 opensostituiscecodecs.open
openvolte riesca a gestire molto bene i caratteri non latini codificati UTF-8 del set unicode, e talvolta fallisce
io.opennon prende un parametro di codifica da quello che posso vedere in Python 2.7.5
io.openaccetta encodinge newlineparametri e li interpreta come Python 3 fa. Diversamente codecs.open, un file aperto con io.opensolleverà TypeError: write() argument 1 must be unicode, not stranche in Python 2.7 se provi a scriverci str( bytes). Un file aperto con codecs.opententerà invece la conversione implicita in unicode, spesso portando a confondere UnicodeDecodeErrors.
In Python 2 ci sono stringhe Unicode e bytestrings. Se usi solo bytestrings, puoi leggere / scrivere su un file aperto con open(). Dopo tutto, le stringhe sono solo byte.
Il problema sorge quando, ad esempio, hai una stringa Unicode e fai quanto segue:
>>> 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)
Quindi qui ovviamente o codifichi esplicitamente la tua stringa unicode in utf-8 o lo usi codecs.openper farlo in modo trasparente.
Se utilizzi solo bytestrings, nessun problema:
>>> example = 'Μου αρέσει Ελληνικά'
>>> open('sample.txt', 'w').write(example)
>>>
Diventa più complicato di questo perché quando concateni una stringa unicode e bytestring con l' +operatore ottieni una stringa unicode. È facile farsi mordere da quello.
Inoltre codecs.opennon gradisce il passaggio di bytestrings con caratteri non ASCII:
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)
Il consiglio sulle stringhe per input / output è normalmente "converti in unicode il prima possibile e torna in bytestrings il più tardi possibile". L' codecs.openutilizzo ti consente di eseguire quest'ultimo molto facilmente.
Fai solo attenzione a dargli stringhe Unicode e non stringhe che potrebbero avere caratteri non ASCII.
u''nel primo esempio. Ciò significa che ho creato una stringa Unicode, non una bytestring. Questa è la differenza tra i due esempi. Nel secondo esempio sto creando una bytestring e scrivere uno di questi su un file va bene. Una stringa Unicode non va bene se stai usando caratteri al di fuori di ASCII.
codecs.open, suppongo, è solo un residuo dei Python 2giorni in cui l'open integrato aveva un'interfaccia molto più semplice e meno funzionalità. In Python 2, built-in opennon accetta un argomento di codifica, quindi se vuoi usare qualcosa di diverso dalla modalità binaria o dalla codifica predefinita, dovrebbe essere usato codecs.open.
In Python 2.6, il modulo io è venuto in aiuto per rendere le cose un po 'più semplici. Secondo la documentazione ufficiale
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.
Detto questo, l'unico utilizzo che mi viene in mente codecs.opennello scenario attuale è per la compatibilità con le versioni precedenti. In tutti gli altri scenari (a meno che tu non stia usando Python <2.6) è preferibile usare io.open. Anche in Python 3.x io.openè lo stesso dibuilt-in open
Nota:
C'è anche una differenza sintattica tra codecs.opene io.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)
codecs.opene io.opendifferiscono in termini di sintassi, restituiscono oggetti di diverso tipo. Inoltre codecs.openfunziona sempre con i file in modalità binaria.
Quando vuoi caricare un file binario, usa
f = io.open(filename, 'b').
Per aprire un file di testo, utilizzare sempre f = io.open(filename, encoding='utf-8')con codifica esplicita.
In python 3 tuttavia openfa la stessa cosa di io.opene può essere usato al suo posto.
Nota:
codecs.openè previsto che diventi deprecato e sostituito daio.opendopo la sua introduzione in python 2.6 . Lo userei solo se il codice deve essere compatibile con le versioni precedenti di Python. Per ulteriori informazioni su codec e unicode in python, vedere Unicode HOWTO .
io.openo codecs.open? 2. codecs.opennon è ancora deprecato, leggi la discussione nella pagina a cui ti sei collegato.
Quando lavori con file di testo e desideri una codifica e una decodifica trasparenti in oggetti Unicode.
Ero in una situazione per aprire un file .asm ed elaborare il file.
#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:
Senza troppi problemi riesco a leggere l'intero file, qualche suggerimento?
codecs.open()è obsoleto in 3.x, poichéopen()ottiene unencodingargomento.