memoryview en Python: buffers sin copia

Publicado el: 28/08/2026
Tempo de leitura: 4 minutos
A close-up shot showcasing the intricate scales of a snake, highlighting texture and color.

Copiar grandes bloques binarios puede convertirse en un coste invisible en aplicaciones Python. Paquetes de red, imágenes, archivos mapeados y arreglos numéricos suelen atravesar varias capas, y cada conversión a un nuevo objeto bytes puede reservar memoria y duplicar datos. memoryview ofrece otra opción: expone una vista sobre cualquier objeto compatible con el protocolo de buffer, permitiendo inspeccionar o modificar regiones sin copiar todo el bloque.

En esta guía aprenderás a crear vistas, cortar buffers sin copias, trabajar con formatos y dimensiones, modificar datos mutables, combinar memoryview con array, mmap, struct y sockets, y evitar problemas de ciclo de vida.

Qué es el protocolo de buffer

El protocolo de buffer permite que un objeto exponga su memoria interna a otros componentes de Python. Tipos como bytes, bytearray y array.array lo implementan, además de muchos objetos de bibliotecas científicas y extensiones nativas.

Un slice normal de bytes crea un objeto nuevo. En cambio, un slice de memoryview normalmente crea otra vista que apunta al mismo almacenamiento.

datos = b"abcdefghijklmnopqrstuvwxyz"
vista = memoryview(datos)
parte = vista[5:10]

print(bytes(parte))  # b'fghij'
print(parte.obj is datos)  # True

Esto resulta útil cuando un parser o pipeline debe examinar distintas zonas de un buffer grande sin generar objetos temporales.

Vistas de solo lectura y escritura

La mutabilidad depende del objeto original. Una vista sobre bytes es de solo lectura. Una vista sobre bytearray puede modificar el almacenamiento original.

buffer = bytearray(b"ABCDE")
vista = memoryview(buffer)
vista[1:4] = b"xyz"

print(buffer)  # bytearray(b'AxyzE')

Los datos asignados deben tener una estructura compatible. Una vista no es una lista redimensionable; representa una región existente con formato y tamaño definidos.

Slices sin copia

Los slices sucesivos siguen compartiendo el mismo objeto base. Así, un parser puede devolver campos como vistas en lugar de copiar cada segmento.

def separar_paquete(paquete: bytes):
    vista = memoryview(paquete)
    version = vista[0:1]
    longitud = vista[1:5]
    payload = vista[5:]
    return version, longitud, payload

Mientras existan vistas activas, los objetos redimensionables no pueden cambiar de tamaño.

datos = bytearray(b"1234")
vista = memoryview(datos)
# datos.extend(b"5")  # BufferError
vista.release()
datos.extend(b"5")

Formato, itemsize y bytes totales

Una vista puede describir elementos mayores que un byte. Sobre array('I'), por ejemplo, expone enteros sin signo en vez de bytes aislados.

from array import array

numeros = array('I', [10, 20, 30, 40])
vista = memoryview(numeros)

print(vista.format)
print(vista.itemsize)
print(vista.nbytes)
print(vista.tolist())

len(vista) suele contar elementos en la primera dimensión, mientras nbytes informa el tamaño total en bytes.

Reinterpretar memoria con cast

cast() cambia la forma de interpretar los mismos bytes. No convierte numéricamente los valores ni crea una copia transformada.

datos = bytearray(range(16))
plana = memoryview(datos)
matriz = plana.cast('B', shape=[4, 4])

print(matriz[2, 3])
matriz[0, 0] = 255
print(datos[0])

El número total de bytes debe seguir siendo compatible. Para layouts binarios estructurados, combina vistas con struct en Python, que controla formatos, offsets y orden de bytes.

Archivos mapeados en memoria

Un archivo mapeado puede exponer su contenido como buffer. Las vistas representan regiones específicas sin leer todo el archivo en objetos separados.

import mmap

with open("datos.bin", "r+b") as archivo:
    with mmap.mmap(archivo.fileno(), 0) as mapa:
        vista = memoryview(mapa)
        cabecera = vista[:64]
        print(bytes(cabecera[:8]))
        cabecera.release()
        vista.release()

Libera todas las vistas antes de cerrar el mapeo. De lo contrario, Python puede lanzar BufferError. Consulta también la guía de mmap en Python.

Recibir datos de sockets en buffers reutilizables

APIs como recv_into() pueden escribir directamente en un buffer existente.

buffer = bytearray(65536)
vista = memoryview(buffer)

# recibidos = sock.recv_into(vista)
# paquete = vista[:recibidos]

Los buffers reutilizables reducen la presión de asignaciones en servidores de alto rendimiento. El diseño debe impedir que una región se reutilice mientras otra tarea todavía la está leyendo.

memoryview frente a bytes

Usa bytes cuando necesites un valor independiente, inmutable y fácil de almacenar o usar como clave. Usa memoryview cuando quieras slices sin copia, modificaciones in-place o interoperabilidad con APIs que aceptan buffers.

bytes(vista) crea una copia. Convierte solo en el límite donde la independencia sea realmente necesaria.

Reglas de ciclo de vida

  • No redimensiones un bytearray mientras existan vistas activas.
  • Libera vistas antes de cerrar un mmap u otro recurso nativo.
  • No conserves una vista indefinidamente si el buffer proviene de un pool reutilizable.
  • Documenta si una API devuelve datos propios o memoria prestada.
  • Usa with memoryview(obj) as vista cuando la liberación determinista mejore la claridad.

Parser binario sin copias intermedias

import struct

CABECERA = struct.Struct("!BI")

def analizar_paquete(datos: bytes):
    vista = memoryview(datos)
    if vista.nbytes < CABECERA.size:
        raise ValueError("paquete incompleto")

    tipo, longitud = CABECERA.unpack_from(vista, 0)
    inicio = CABECERA.size
    fin = inicio + longitud

    if fin > vista.nbytes:
        raise ValueError("payload truncado")

    payload = vista[inicio:fin]
    return tipo, payload

El payload comparte memoria con datos. El llamador puede procesarlo directamente y crear una copia únicamente si necesita persistirlo.

Cuándo merece la pena

Para scripts pequeños y valores diminutos, los slices normales suelen ser más simples. memoryview destaca en pipelines binarios, redes, multimedia, análisis de archivos grandes, bibliotecas científicas e integración con código nativo.

Mide antes de optimizar. Herramientas como tracemalloc ayudan a comprobar si las copias temporales afectan realmente a la memoria. El código zero-copy también introduce reglas de propiedad, así que el beneficio debe justificar la complejidad.

Conclusión

memoryview es la interfaz estándar de Python para acceder a buffers prestados. Permite slices sin copia, vistas editables, metadatos de formato, casts multidimensionales e integración con array, struct, mmap y sockets.

La documentación oficial de memoryview en Python detalla operaciones y formatos. Úsalo cuando copiar sea un coste medible, manteniendo explícitas la propiedad, la mutabilidad y la duración del buffer.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Código Python en pantalla representando EnumDict y enumeraciones avanzadas
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    EnumDict: personaliza Enums con validación

    Aprende EnumDict en Python para personalizar EnumType, validar miembros y crear enumeraciones avanzadas con seguridad.

    Ler mais

    Tempo de leitura: 4 minutos
    11/10/2026
    Rack de servidores que representa el balanceo de conexiones con SO_REUSEPORT_LB en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    SO_REUSEPORT_LB: reparte conexiones entre workers

    Aprende SO_REUSEPORT_LB en Python para distribuir conexiones entre workers con pruebas, portabilidad y cierre ordenado.

    Ler mais

    Tempo de leitura: 5 minutos
    11/10/2026
    Código Python asíncrono en un portátil para inspect.markcoroutinefunction
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    markcoroutinefunction: detecta wrappers async

    Aprende inspect.markcoroutinefunction en Python para identificar wrappers asíncronos, integrar frameworks y evitar detecciones incorrectas.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Código Python para recorrer carpetas y archivos con Path.walk
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    Path.walk: recorre directorios con seguridad

    Aprende Path.walk en Python para recorrer directorios, filtrar archivos, tratar errores y controlar la travesía con seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Depuración de un proceso Python en terminal con código
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pdb -p: depura procesos Python en ejecución

    Aprende a conectar pdb a un proceso Python en ejecución, inspeccionar la pila y diagnosticar bloqueos de forma segura.

    Ler mais

    Tempo de leitura: 6 minutos
    09/10/2026
    Código Python para representar fracciones exactas
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    fractions.from_number: convierte números en fracciones

    Aprende fractions.from_number en Python para convertir números en fracciones exactas, controlar precisión, validar entradas y evitar redondeos inesperados.

    Ler mais

    Tempo de leitura: 4 minutos
    09/10/2026