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

    A developer typing code on a laptop with a Python book beside in an office.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    Protocol en Python: tipado estructural

    Aprende Python Protocol para tipado estructural, contratos genéricos, callbacks, runtime_checkable, pruebas e inyección de dependencias.

    Ler mais

    Tempo de leitura: 4 minutos
    28/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tracemalloc en Python: rastrea memoria

    Aprende tracemalloc en Python para medir picos, crear y comparar snapshots, filtrar asignaciones y diagnosticar crecimiento de memoria.

    Ler mais

    Tempo de leitura: 6 minutos
    28/08/2026
    Detailed shot of a Jungle Carpet Python (Morelia spilota cheynei) in its natural habitat.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    queue en Python: comunica threads

    Aprende queue en Python para comunicar threads con FIFO, LIFO, prioridad, backpressure, task tracking, sentinelas y shutdown seguro.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    Flat lay of a complete toolset neatly organized in a workshop setting, essential for auto repair tasks.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    selectors en Python: varios sockets

    Aprende selectors en Python para multiplexar sockets, gestionar lecturas y escrituras parciales, buffers, timeouts, wakeup y backpressure.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    Detailed close-up texture of a snake's patterned skin showcasing natural patterns and scales.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    contextvars en Python: contexto async

    Aprende contextvars en Python para contexto por task, request IDs, logging, copy_context, propagación a threads y restauración con tokens.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    Person writing appointments on a calendar with a blue pen. High angle view.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    sched en Python: programa eventos

    Aprende sched en Python para programar eventos, usar prioridades, cancelar tareas, crear recurrencia sin drift e integrar executors.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026