Hay dos formas de abrir un archivo de texto en Python:
f = open(filename)
Y
import codecs
f = codecs.open(filename, encoding="utf-8")
¿Cuándo es codecs.open
preferible open
?
Hay dos formas de abrir un archivo de texto en Python:
f = open(filename)
Y
import codecs
f = codecs.open(filename, encoding="utf-8")
¿Cuándo es codecs.open
preferible open
?
Respuestas:
Desde Python 2.6, una buena práctica es usar io.open()
, que también toma un encoding
argumento, como el ahora obsoleto codecs.open()
. En Python 3, io.open
es un alias para el open()
archivo integrado. Así que io.open()
funciona en Python 2.6 y todas las versiones posteriores, incluido Python 3.4. Ver documentos: http://docs.python.org/3.4/library/io.html
Ahora, para la pregunta original: al leer texto (incluido "texto sin formato", HTML, XML y JSON) en Python 2, siempre debe usarlo io.open()
con una codificación explícita o open()
con una codificación explícita en Python 3. Si lo hace, significa que obtiene correctamente decodificado Unicode, o obtiene un error de inmediato, lo que facilita la depuración.
El "texto sin formato" ASCII puro es un mito del pasado distante. El texto en inglés adecuado utiliza comillas entrecruzadas, guiones en forma de em, viñetas, € (signos de euro) e incluso diéresis (¨). ¡No seas ingenuo! (¡Y no olvidemos el patrón de diseño de fachada!)
Debido a que ASCII puro no es una opción real, open()
sin una codificación explícita solo es útil para leer archivos binarios .
io.open()
para texto, y open()
solo para binario. La implicación es que codecs.open()
no se prefiere en absoluto.
open
y codecs.open
, y específicamente cuándo es preferible este último al primero. Una respuesta que ni siquiera menciona codecs.open
no puede responder esa pregunta.
codecs.open()
era correcto usarlo), entonces no hay una respuesta "correcta" sobre cuándo usarlo. La respuesta es usar io.open()
en su lugar. Es como si preguntara "¿cuándo debo usar una llave para clavar un clavo en una pared?". La respuesta correcta es "usa un martillo".
Personalmente, siempre uso a codecs.open
menos que haya una clara necesidad identificada de usar open
**. La razón es que ha habido muchas ocasiones en las que me ha mordido que la entrada de utf-8 se cuela en mis programas. "Oh, solo sé que siempre será ascii" tiende a ser una suposición que se rompe a menudo.
Asumir 'utf-8' como la codificación predeterminada tiende a ser una opción predeterminada más segura en mi experiencia, ya que ASCII se puede tratar como UTF-8, pero lo contrario no es cierto. Y en aquellos casos en los que realmente sé que la entrada es ASCII, lo sigo haciendo, codecs.open
ya que creo firmemente en "lo explícito es mejor que lo implícito" .
** - en Python 2.x, como el comentario sobre la pregunta dice en Python 3 open
reemplazacodecs.open
open
veces puede manejar muy bien los caracteres no latinos codificados en UTF-8 del conjunto Unicode, y a veces falla
io.open
no toma un parámetro de codificación de lo que puedo ver en Python
io.open
acepta encoding
y newline
parámetros y interpreta como Python 3 hace. A diferencia codecs.open
, un archivo abierto con io.open
aumentará TypeError: write() argument 1 must be unicode, not str
incluso en Python 2.7 si intenta escribir str
( bytes
) en él. En su lugar, un archivo abierto con codecs.open
intentará una conversión implícita a unicode
, lo que a menudo genera confusiones UnicodeDecodeError
.
En Python 2 hay cadenas unicode y cadenas de bytes. Si solo usa cadenas de bytes, puede leer / escribir en un archivo abierto con open()
muy bien. Después de todo, las cadenas son solo bytes.
El problema surge cuando, digamos, tiene una cadena Unicode y hace lo siguiente:
>>> 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)
Así que aquí, obviamente, codifica explícitamente su cadena Unicode en utf-8 o lo usa codecs.open
para hacerlo de forma transparente.
Si solo usa cadenas de bytes, entonces no hay problemas:
>>> example = 'Μου αρέσει Ελληνικά'
>>> open('sample.txt', 'w').write(example)
>>>
Se complica más que esto porque cuando concatenas una cadena unicode y una cadena de bytes con el +
operador, obtienes una cadena unicode. Es fácil que te muerda ese.
Tampoco codecs.open
le gusta que se pasen cadenas de bytes con caracteres no 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)
El consejo sobre cadenas para entrada / salida es normalmente "convertir a Unicode lo antes posible y volver a cadenas de bytes lo más tarde posible". El uso le codecs.open
permite hacer esto último muy fácilmente.
Solo tenga cuidado de darle cadenas Unicode y no cadenas de bytes que pueden tener caracteres no ASCII.
u''
en el primer ejemplo. Esto significa que creé una cadena Unicode, no una cadena de bytes. Ésta es la diferencia entre los dos ejemplos. En el segundo ejemplo, estoy creando una cadena de bytes y escribir una de esas en un archivo está bien. Una cadena Unicode no está bien si está utilizando caracteres fuera de ASCII.
codecs.open
, supongo, es solo un remanente de los Python 2
días en que el sistema abierto incorporado tenía una interfaz mucho más simple y menos capacidades. En Python 2, lo integrado open
no acepta un argumento de codificación, por lo que si desea usar algo que no sea el modo binario o la codificación predeterminada, se suponía que debía usar codecs.open.
En Python 2.6
, el módulo io vino en ayuda para simplificar un poco las cosas. Según la documentación oficial
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.
Dicho esto, el único uso que se me ocurre codecs.open
en el escenario actual es la compatibilidad con versiones anteriores. En todos los demás escenarios (a menos que esté usando Python <2.6), es preferible usar io.open
. También en Python 3.x
io.open
es lo mismo quebuilt-in open
Nota:
También hay una diferencia sintáctica entre codecs.open
y 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
y io.open
difieren en términos de sintaxis, devuelven objetos de diferente tipo. También codecs.open
siempre funciona con archivos en modo binario.
Cuando desee cargar un archivo binario, use
f = io.open(filename, 'b')
.
Para abrir un archivo de texto, utilícelo siempre f = io.open(filename, encoding='utf-8')
con codificación explícita.
Sin embargo, en python 3open
hace lo mismo que io.open
y se puede usar en su lugar.
Nota:
codecs.open
está previsto que quede obsoleto y se sustituya porio.open
después de su introducción en Python 2.6 . Solo lo usaría si el código necesita ser compatible con versiones anteriores de Python. Para obtener más información sobre códecs y Unicode en Python, consulte Unicode HOWTO .
io.open
o codecs.open
? 2. codecs.open
aún no está en desuso, lea la discusión en la página a la que vinculó.
Cuando trabaja con archivos de texto y desea codificación y decodificación transparente en objetos Unicode.
Estaba en una situación para abrir un archivo .asm y procesar el archivo.
#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:
Sin muchos problemas puedo leer todo el archivo, ¿alguna sugerencia?
codecs.open()
está obsoleto en 3.x, ya queopen()
gana unencoding
argumento.