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.open
preferibile 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.open
preferibile 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 encoding
argomento, 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.
open
e codecs.open
, e in particolare quando il secondo è preferibile al primo. Una risposta che non è nemmeno menzionata codecs.open
non 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.open
come io sono un convinto sostenitore "esplicito è meglio che implicito" .
** - in Python 2.x, come il commento sulla domanda afferma in Python 3 open
sostituiscecodecs.open
open
volte riesca a gestire molto bene i caratteri non latini codificati UTF-8 del set unicode, e talvolta fallisce
io.open
non prende un parametro di codifica da quello che posso vedere in Python 2.7.5
io.open
accetta encoding
e newline
parametri e li interpreta come Python 3 fa. Diversamente codecs.open
, un file aperto con io.open
solleverà TypeError: write() argument 1 must be unicode, not str
anche in Python 2.7 se provi a scriverci str
( bytes
). Un file aperto con codecs.open
tenterà invece la conversione implicita in unicode
, spesso portando a confondere UnicodeDecodeError
s.
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.open
per 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.open
non 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.open
utilizzo 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 2
giorni in cui l'open integrato aveva un'interfaccia molto più semplice e meno funzionalità. In Python 2, built-in open
non 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.open
nello 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.open
e 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.open
e io.open
differiscono in termini di sintassi, restituiscono oggetti di diverso tipo. Inoltre codecs.open
funziona 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 open
fa la stessa cosa di io.open
e può essere usato al suo posto.
Nota:
codecs.open
è previsto che diventi deprecato e sostituito daio.open
dopo 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.open
o codecs.open
? 2. codecs.open
non è 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 unencoding
argomento.