El módulo `io` en Python
Este artículo explica el módulo io en Python.
Explicaremos el módulo io en Python con ejemplos prácticos.
YouTube Video
El módulo io en Python
El procesamiento de entrada/salida forma la base de todo tipo de operaciones de datos, como archivos, redes y E/S estándar. El módulo io de Python proporciona un conjunto de clases abstractas que unifican estas operaciones de entrada/salida. El concepto clave para entender este módulo es la idea de una "corriente" (stream).
¿Qué es un flujo?
Una corriente es un flujo abstracto para leer y escribir datos de forma secuencial y continua.
Cuando se leen los contenidos de archivos byte por byte o se envían y reciben datos a través de una red, todo esto puede tratarse como corrientes de datos.
Al abstraer este mecanismo, archivos, memoria y redes—diferentes fuentes de entrada/salida—pueden manejarse con operaciones comunes como leer y escribir.
El módulo io de Python proporciona una interfaz unificada para corrientes, permitiendo el manejo eficiente de datos tanto de texto como binarios.
Estructura básica del módulo io
El módulo io tiene una jerarquía de tres capas según la naturaleza de las corrientes.
-
Capa Cruda (
RawIOBase)RawIOBasemaneja la entrada/salida de bytes a nivel más bajo, como descriptores de archivos del sistema operativo y dispositivos. -
Capa Búfer (
BufferedIOBase)BufferedIOBaseproporciona una caché (búfer) para mejorar la eficiencia de la E/S.BufferedReaderyBufferedWriterson ejemplos típicos. -
Capa de Texto (
TextIOBase)TextIOBaseconvierte secuencias de bytes en cadenas y gestiona la codificación. Normalmente, al abrir un archivo con la funciónopen(), se utilizaTextIOWrapperde esta capa.
Gracias a esta estructura, el módulo io separa claramente la entrada/salida de texto y binaria, permitiendo combinaciones flexibles.
Estructura básica del módulo io
RawIOBase maneja los descriptores de archivos OS en la capa más baja, BufferedIOBase agrega una caché encima, y la capa superior TextIOBase gestiona conversiones de cadenas.
1import io
2
3# Check the core base classes hierarchy
4print(io.IOBase.__subclasses__())- Este código sirve para comprobar el grupo de clases abstractas que heredan de
IOBase. Se pueden verTextIOBase,BufferedIOBaseyRawIOBase, confirmando la estructura jerárquica.
io.IOBase: La clase base de todas
IOBase es la clase abstracta base para todos los objetos de E/S, definiendo métodos comunes como close(), flush() y seekable(). Raramente se usa directamente y usualmente se accede a través de clases derivadas.
1import io
2
3f = io.StringIO("data")
4print(f.seekable()) # True
5print(f.readable()) # True
6print(f.writable()) # True
7f.close()- Este ejemplo muestra que los métodos comunes de
IOBasetambién pueden usarse en las clases superiores.seekable()yreadable()son útiles para comprobar las propiedades de una corriente.
io.RawIOBase: La capa de más bajo nivel
RawIOBase es la capa más cercana al descriptor de archivos del sistema operativo y no realiza almacenamiento en búfer. La implementación típica es FileIO, que lee y escribe por byte.
1import io, os
2
3# Create a low-level FileIO object (no buffering)
4fd = os.open('raw_demo.bin', os.O_RDWR | os.O_CREAT)
5raw = io.FileIO(fd, mode='w+')
6raw.write(b'abc123')
7raw.seek(0)
8print(raw.read(6)) # b'abc123'
9raw.close()FileIOes una implementación concreta deRawIOBase; todas las lecturas y escrituras se realizan comobytes. La eficiencia puede mejorarse combinándolo con la capa superiorBufferedIOBase.
io.BufferedIOBase: Capa intermedia (con búfer)
BufferedIOBase es una capa intermedia que realiza almacenamiento en búfer, haciendo el acceso al disco más eficiente. Las implementaciones principales son BufferedReader, BufferedWriter, BufferedRandom y BufferedRWPair.
1import io
2
3# Create a buffered binary stream on top of a BytesIO (simulate file)
4base = io.BytesIO()
5buffered = io.BufferedWriter(base)
6buffered.write(b'Python IO buffering')
7buffered.flush()
8base.seek(0)
9print(base.read()) # b'Python IO buffering'- En este ejemplo, los datos escritos con
BufferedWriterse almacenan temporalmente en un búfer de memoria y se transfieren a la capa inferior al llamar aflush().
Ejemplo de BufferedReader
BufferedReader es un flujo en búfer de solo lectura que permite lecturas eficientes con peek() y read().
1import io
2
3stream = io.BytesIO(b"1234567890")
4reader = io.BufferedReader(stream)
5print(reader.peek(5)) # b'12345' (non-destructive)
6print(reader.read(4)) # b'1234'
7print(reader.read(3)) # b'567'peek()solo 'espía' los datos y no mueve el puntero. Al combinarlo conread(), puedes controlar el almacenamiento en búfer de manera flexible.
io.TextIOBase: Capa solo de texto
TextIOBase es una capa de abstracción para manejar cadenas de texto, realizando internamente la decodificación y codificación. Una clase de implementación típica es TextIOWrapper.
1import io
2
3# Wrap a binary stream to handle text encoding
4binary = io.BytesIO()
5text_stream = io.TextIOWrapper(binary, encoding='utf-8')
6text_stream.write("\u3053\u3093\u306B\u3061\u306F")
7text_stream.flush()
8
9# Reset stream position
10binary.seek(0)
11
12# Read bytes once
13data = binary.read()
14
15# Show both raw bytes and decoded text
16print("Raw bytes:", data)
17print("Decoded text:", data.decode('utf-8'))- En este ejemplo,
TextIOWrappercodifica la cadena a UTF-8 y la escribe en la corriente binaria subyacente.
Ejemplo de lectura con TextIOWrapper
La decodificación se realiza automáticamente al leer.
1import io
2
3binary_data = io.BytesIO("Python I/O".encode('utf-8'))
4text_reader = io.TextIOWrapper(binary_data, encoding='utf-8')
5print(text_reader.read()) # 'Python I/O'TextIOWrappersirve como la clase fundamental para la E/S de texto y forma la base para casi todas las operaciones de archivos de alto nivel.
io.StringIO: Corriente de texto en memoria
StringIO es una clase que permite manejar cadenas de texto en memoria como si fueran archivos. Es útil para pruebas de E/S y generación de datos temporales.
1import io
2
3text_buf = io.StringIO()
4text_buf.write("In-memory text stream")
5text_buf.seek(0)
6print(text_buf.read()) # 'In-memory text stream'StringIOpermite operaciones similares a archivos sin usar el disco y es ampliamente utilizado en pruebas unitarias.
io.BytesIO: Corriente binaria en memoria
BytesIO es una clase de archivo en memoria para manejar secuencias de bytes (bytes). Es útil para situaciones como procesamiento binario o compresión de datos donde no se desea utilizar archivos.
1import io
2
3buf = io.BytesIO()
4buf.write(b'\x01\x02\x03')
5buf.seek(0)
6print(list(buf.read())) # [1, 2, 3]BytesIOtiene la misma interfaz queBufferedIOBasey puede usarse como sustituto de muchas APIs de archivos.
Corrientes personalizadas (creación de clases originales)
Las clases en io son extensibles, permitiendo crear tus propias clases de corrientes. A continuación se muestra un ejemplo de una subclase de TextIOBase que pone en mayúscula todo el texto al escribir.
1import io
2
3class UpperTextIO(io.TextIOBase):
4 def __init__(self):
5 self.buffer = ""
6 def write(self, s):
7 self.buffer += s.upper()
8 return len(s)
9
10u = UpperTextIO()
11u.write("hello io")
12print(u.buffer) # "HELLO IO"- Mientras cumplas el contrato de
TextIOBase, puedes definir cualquier comportamiento personalizado como este. También es fácil extender las corrientes para usos específicos, como archivos y redes.
Resumen
El módulo io organiza el procesamiento de entrada/salida en una jerarquía de clases abstractas y concretas.
RawIOBasees una clase para la entrada/salida de bytes a nivel de sistema operativo.BufferedIOBasees una clase que ofrece una capa de caché eficiente.TextIOBasees una clase que gestiona la lectura y escritura de cadenas.StringIOyBytesIOson clases que proporcionan corrientes en memoria.
Comprender estas clases te permite captar con precisión el funcionamiento del sistema de E/S de Python y aplicarlas a operaciones de archivos, comunicación en red y diseño de corrientes para pruebas.
Puedes seguir el artículo anterior utilizando Visual Studio Code en nuestro canal de YouTube. Por favor, también revisa nuestro canal de YouTube.