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.openpreferible 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.openpreferible open?
Respuestas:
Desde Python 2.6, una buena práctica es usar io.open(), que también toma un encodingargumento, como el ahora obsoleto codecs.open(). En Python 3, io.openes 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.
openy codecs.open, y específicamente cuándo es preferible este último al primero. Una respuesta que ni siquiera menciona codecs.openno 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.openmenos 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.openya 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 openreemplazacodecs.open
openveces puede manejar muy bien los caracteres no latinos codificados en UTF-8 del conjunto Unicode, y a veces falla
io.openno toma un parámetro de codificación de lo que puedo ver en Python
io.openacepta encodingy newlineparámetros y interpreta como Python 3 hace. A diferencia codecs.open, un archivo abierto con io.openaumentará TypeError: write() argument 1 must be unicode, not strincluso en Python 2.7 si intenta escribir str( bytes) en él. En su lugar, un archivo abierto con codecs.openintentará 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.openpara 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.openle 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.openpermite 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 2días en que el sistema abierto incorporado tenía una interfaz mucho más simple y menos capacidades. En Python 2, lo integrado openno 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.openen 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.openes lo mismo quebuilt-in open
Nota:
También hay una diferencia sintáctica entre codecs.openy 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.openy io.opendifieren en términos de sintaxis, devuelven objetos de diferente tipo. También codecs.opensiempre 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.openy se puede usar en su lugar.
Nota:
codecs.openestá previsto que quede obsoleto y se sustituya porio.opendespué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.openo codecs.open? 2. codecs.openaú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 unencodingargumento.