Diferencia entre abierto y codecs.open en Python

8 minutos de lectura

avatar de usuario
BlogueroConnor

Hay dos formas de abrir un archivo de texto en Python:

f = open(filename)

Y

import codecs
f = codecs.open(filename, encoding="utf-8")

Cuando es codecs.open preferible a open?

  • Tenga en cuenta que codecs.open() está obsoleto en 3.x, ya que open() gana un encoding argumento.

    – Ignacio Vázquez-Abrams

    9 de marzo de 2011 a las 19:05

  • También hay una tercera forma (al menos en Python 2.x): `f = archivo (nombre de archivo)’

    – Adam Parkin

    1 de noviembre de 2012 a las 15:53

  • @IgnacioVazquez-Abrams ¿Hay algún enlace que codecs.open() ¿es obsoleto? No creo que esto en python3 docs: docs.python.org/3.7/library/codecs.html

    – varela

    17 de abril de 2019 a las 12:25

  • @varela: la página de documentación de Python que mencionó dice: “el open() incorporado y el módulo io asociado son el enfoque recomendado para trabajar con archivos de texto codificados”

    – Luciano Ramalho

    10 de mayo de 2019 a las 2:10

Desde Python 2.6, una buena práctica es usar io.open()que también toma un encoding argumento, como el ya obsoleto codecs.open(). En Python 3, io.open es un alias para el open() incorporado. Asi que io.open() funciona en Python 2.6 y todas las versiones posteriores, incluida Python 3.4. Ver documentos: http://docs.python.org/3.4/library/io.html

Ahora, para la pregunta original: al leer texto (incluyendo “texto sin formato”, HTML, XML y JSON) en Python 2 debe siempre usar 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 Unicode correctamente decodificado, o recibe un error de inmediato, lo que hace que sea mucho más fácil de depurar.

El “texto sin formato” ASCII puro es un mito del pasado lejano. El texto en inglés correcto usa comillas curvas, guiones largos, viñetas, € (símbolos del 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 es solamente útil para leer binario archivos

  • @ForeverWintr La respuesta está bastante clara ahí: use io.open() para texto y open() solo para binario. La implicación es que codecs.open() no se prefiere en absoluto.

    – Bdoserror

    4 de abril de 2017 a las 18:11


  • @Bdoserror, Hay un respuesta allí, claramente, pero no es una respuesta a la pregunta que se hizo. La pregunta era sobre la diferencia entre open y codecs.open, y en concreto cuando este último es preferible al primero. Una respuesta que ni siquiera menciona codecs.open no puedo responder a esa pregunta.

    – ForeverWintr

    04/04/2017 a las 18:30

  • @ForeverWintr Si el OP le preguntó al equivocado pregunta (es decir, con la suposición de que codecs.open() fue correcto usar), entonces no hay una respuesta “correcta” sobre cuándo usarlo. La respuesta es usar io.open() en cambio. Es como si pregunto “¿cuándo debo usar una llave inglesa para clavar un clavo en una pared?”. La respuesta correcta es “usar un martillo”.

    – Bdoserror

    5 de abril de 2017 a las 17:47

Personalmente yo siempre usar codecs.open a menos que haya una clara necesidad identificada de usar open**. La razón es que ha habido muchas veces en las que he sido mordido por la entrada de utf-8 en mis programas. “Oh, solo sé que siempre será ascii” tiende a ser una suposición que se rompe a menudo.

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

** – en Python 2.x, como dice el comentario en la pregunta en Python 3 open reemplaza codecs.open

  • lo que realmente no entiendo es por qué open a veces puede manejar muy bien los caracteres no latinos codificados en UTF-8 del conjunto Unicode, y a veces falla miserablemente…

    – cedbeu

    27 de marzo de 2013 a las 18:45

  • Esto tiene sentido para mí. io.open no toma un parámetro de codificación de lo que puedo ver en python 2.7.5

    – Radtek

    23 de enero de 2018 a las 15:52

  • @radtek, tienes razón en que esto no está documentado; sin embargo (al menos en 2.7.12) io.open acepta encoding y newline parámetros y los interpreta como lo hace Python 3. A diferencia de codecs.openun archivo abierto con io.open elevará TypeError: write() argument 1 must be unicode, not str incluso en Python 2.7 si intenta escribir str (bytes) a ello. Un archivo abierto con codecs.open en su lugar, intentará la conversión implícita a unicodelo que a menudo conduce a confusión UnicodeDecodeErrors.

    – jochietoch

    2 de septiembre de 2018 a las 7:49

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, por ejemplo, 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, codificas explícitamente tu cadena Unicode en utf-8 o usas codecs.open para hacerlo por ti de forma transparente.

Si solo usa cadenas de bytes, no hay problema:

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

Se vuelve más complicado que esto porque cuando concatenas una cadena unicode y bytestring con el + operador obtienes una cadena Unicode. Es fácil ser mordido por ese.

También codecs.open no le gustan las cadenas de bytes con caracteres no ASCII que se pasan:

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 normalmente es “convertir a Unicode lo antes posible y volver a cadenas de bytes lo más tarde posible”. Usando codecs.open le permite hacer esto último muy fácilmente.

Solo tenga cuidado de darle cadenas Unicode y no cadenas de bytes que pueden tener caracteres que no sean ASCII.

  • ¿Puedes explicar tu segundo ejemplo? Parece ser idéntico a su primer ejemplo, entonces, ¿por qué el resultado sería diferente?

    –Chris Johnson

    27 dic 2016 a las 21:33

  • Tenga en cuenta el uso de la u'' en el primer ejemplo. Esto significa que creé una cadena Unicode, no una cadena de bytes. Esta es la diferencia entre los dos ejemplos. En el segundo ejemplo, estoy creando una cadena de bytes y escribiendo uno de ellos en un archivo está bien. Una cadena Unicode no está bien si usa caracteres fuera de ASCII.

    – Mandíbula79

    6 de febrero de 2017 a las 11:04


Cuando necesite abrir un archivo que tenga cierta codificación, usaría el codecs módulo.

avatar de usuario
aquí para aprender

codecs.opensupongo, es sólo un remanente de la Python 2 días en que el abierto incorporado tenía una interfaz mucho más simple y menos capacidades. En Python 2, incorporado open no toma 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 usarse codecs.open.

En Python 2.6, el módulo io vino en ayuda para hacer las cosas un poco más simples. Según el oficial documentación

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.

Habiendo dicho eso, el único uso que se me ocurre codecs.open en el escenario actual es para la compatibilidad con versiones anteriores. En todos los demás escenarios (a menos que esté usando Python io.open. También en Python 3.x io.open es lo mismo que built-in open

Nota:

Hay una diferencia sintáctica entre 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)

  • No solo 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.

    – wombatónfuego

    28 de abril de 2019 a las 22:27

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

  • Para abrir un archivo de texto, utilice siempre f = io.open(filename, encoding='utf-8') con codificación explícita.

En pitón 3 sin embargo open hace lo mismo que io.open y se puede utilizar en su lugar.

Nota: codecs.open está planeado para convertirse obsoleto y reemplazado por io.open después de su introducción en pitón 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 la CÓMO Unicode.

  • No solo 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.

    – wombatónfuego

    28 de abril de 2019 a las 22:27

avatar de usuario
gato más más

Cuando trabaja con archivos de texto y desea codificar y decodificar de forma transparente objetos Unicode.

¿Ha sido útil esta solución?