Diferencia entre open y codecs.open en Python

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 preferible open codecs.open ?

Desde Python 2.6, una buena práctica es usar io.open() , que también tiene un argumento de encoding , como los codecs.open() ya obsoletos. En Python 3, io.open es un alias para el open() incorporado. Así que io.open() funciona en Python 2.6 y en todas las versiones posteriores, incluida Python 3.4. Consulte los 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 usar io.open() con una encoding explícita, o open() con una encoding explícita en Python 3. Hacerlo significa que puedes decodificar Unicode correctamente, o recibir un error de inmediato, lo que hace que sea mucho más fácil de depurar.

El “texto simple” ASCII puro es un mito del pasado lejano. El texto en inglés adecuado utiliza citas en forma de rizos, guiones de emergencia, viñetas, euros (signos del euro) e incluso diéresis (¨). ¡No seas ingenuo! (¡Y no olvidemos el patrón de diseño de la Fachada!)

Debido a que ASCII puro no es una opción real, open() sin una encoding explícita solo es útil para leer archivos binarios .

Personalmente, siempre uso codecs.open menos que haya una necesidad claramente identificada de usar open **. La razón es que ha habido muchas veces en las que me han mordido al tener la entrada de utf-8 en mis progtwigs. “Oh, solo sé que siempre será ascii” tiende a ser una suposición que se rompe a menudo.

Suponiendo que ‘utf-8’ como la encoding predeterminada tiende a ser una opción predeterminada más segura en mi experiencia, ya que ASCII puede tratarse como UTF-8, pero lo contrario no es cierto. Y en aquellos casos en los que realmente que la entrada es ASCII, todavía hago codecs.open porque soy un firme creyente en que “explícito es mejor que implícito” .

** – en Python 2.x, ya que el comentario sobre los estados de la pregunta en Python 3 open reemplaza a codecs.open

En Python 2 hay cadenas de caracteres unicode y bytestrings. Si solo usas bytestrings, puedes leer / escribir en un archivo abierto con open() muy bien. Después de todo, las cadenas son sólo bytes.

El problema surge cuando, por ejemplo, tienes una cadena Unicode y haces lo siguiente:

 >>> example = u'Μου αρέσει Ελληνικά' >>> open('sample.txt', 'w').write(example) Traceback (most recent call last): File "", line 1, in  UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128) 

Así que aquí obviamente codificas explícitamente tu cadena Unicode en utf-8 o usas codecs.open para hacerlo de forma transparente.

Si solo usas bytestrings, entonces no hay problemas:

 >>> example = 'Μου αρέσει Ελληνικά' >>> open('sample.txt', 'w').write(example) >>> 

Se involucra más que esto porque cuando concatena un string unicode y bytring con el operador + se obtiene un string unicode. Fácil de ser mordido por ese.

También a codecs.open no le gustan las secuencias de caracteres con caracteres que no son ASCII que se pasan en:

 codecs.open('test', 'w', encoding='utf-8').write('Μου αρέσει') Traceback (most recent call last): File "", line 1, in  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 las cadenas para entrada / salida es normalmente “convertir a Unicode lo antes posible y volver a las secuencias de caracteres lo más tarde posible”. El uso de codecs.open permite hacer esto último muy fácilmente.

Solo tenga cuidado de asignarle cadenas Unicode y no secuencias de caracteres que puedan tener caracteres que no sean ASCII.

Cuando necesite abrir un archivo que tenga cierta encoding, usará el módulo de codecs .

codecs.open , supongo, es solo un remanente de Python 2 días cuando la apertura incorporada tenía una interfaz mucho más simple y menos capacidades. En Python 2, la función de open incorporada no requiere un argumento de encoding, por lo que si desea usar un modo distinto al binario o la encoding predeterminada, se debe usar codecs.open.

En Python 2.6 , el módulo io fue de ayuda para hacer las cosas un poco más simples. 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 puedo pensar de 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 que la función built-in open

Nota:

Existe una diferencia sintáctica entre los codecs.open y io.open también.

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) 

Cuando trabaja con archivos de texto y desea una encoding y deencoding transparentes en objetos Unicode.

  • Cuando desee cargar un archivo binario, use f = open(filename, 'b') .

  • Para abrir un archivo de texto, use f = io.open(filename, encoding='utf-8') .

Sin embargo, en Python 3, open(filename, encoding='utf-8') hace lo mismo y puede usarse en su lugar.

Nota: codecs.open ahora está en desuso y reemplazado por io.open después de su introducción en Python 2.6 . Para obtener más información sobre los códecs y Unicode en Python, consulte el CÓMO de Unicode .