Series

Estructuras de datos en Python: Arreglos (arrays)

Leodanis Pozo Ramos
Leodanis Pozo Ramos
23 nov 2025 6 min
Estructuras de datos en Python: Arreglos (arrays)

Los arreglos o arrays son una de las estructuras de datos más usadas en programación. Proporcionan una forma de almacenar un número fijo de elementos en una secuencia.

En este artículo, aprenderás cómo implementar un arreglo en Python, incluyendo sus operaciones y características principales.

¿Qué es un arreglo o array?

Un arreglo es una colección de elementos, cada uno identificado por un índice entero. Las características fundamentales de un arreglo incluyen las siguientes:

  • Tamaño fijo: El tamaño o número de elementos del arreglo se determina al crearlo y no se puede cambiar.
  • Acceso aleatorio: Los elementos se pueden acceder directamente usando índices que comienzan en 0.
  • Homogéneo o heterogéneo: Los arreglos pueden almacenar elementos del mismo tipo de dato o de tipos mixtos, dependiendo de la implementación.

En Python, los arreglos no están integrados como una estructura de datos primitiva. La biblioteca estándar incluye el tipo array.array para trabajar con datos numéricos homogéneos, pero en este artículo implementarás tu propio arreglo usando el módulo ctypes para tener un mayor control de bajo nivel.

A través de ste ejercicio, podrás obtener una serie de habilidades fundamentales en Python, como puede ser el uso de clases y de métodos especiales, también conocidos como métodos mágicos o dunder.

Operaciones comunes en un arreglo

A continuación, un resumen de las operaciones que soportará tu arreglo:

Operación Descripción
array = Array(size) Construye un arreglo que puede contener size elementos.
array[index] Accede al elemento en index.
array[index] = value Asigna value al elemento en index.
array.clear([value]) Restablece todos los elementos del arreglo, asignándoles el valor value o None.
len(array) Devuelve la longitud del arreglo.
item in array Devuelve True si item está contenido en el arreglo y False si no lo está.
for item in array: ... Itera sobre los elementos del arreglo.
for item in reversed(array): ... Itera sobre los elementos en orden inverso.

Implementación de un arreglo en Python

A continuación encontrarás la implementación del arreglo en Python:

import ctypes
from typing import Any, Generator, Optional

class Array:
    def __init__(self, size: int) -> None:
        if size <= 0:
            raise ValueError("Array size must be a positive integer")
        self._size = size
        self._data = (ctypes.py_object * self._size)()
        self._type: Optional[type] = None
        self.clear()

    def clear(self, value: Optional[Any] = None) -> None:
        if self._type is not None and value is not None and not isinstance(value, self._type):
            raise TypeError(f"Expected type {self._type}, got {type(value)}")
        for i in range(self._size):
            self._data[i] = value

    def __len__(self) -> int:
        return self._size

    def __contains__(self, value: Any) -> bool:
        for item in self._data:
            if item == value:
                return True
        return False

    def _check_index(self, index: int) -> None:
        if not 0 <= index < self._size:
            raise IndexError(
                f"Index out of range: {index}. "
                f"Valid range: 0 to {self._size - 1}"
            )

    def __getitem__(self, index: int) -> Any:
        self._check_index(index)
        return self._data[index]

    def __setitem__(self, index: int, value: Any) -> None:
        if self._type is None and value is not None:
            self._type = type(value)
        elif value is not None and not isinstance(value, self._type):
            raise TypeError(f"Expected type {self._type}, got {type(value)}")
        self._check_index(index)
        self._data[index] = value

    def __iter__(self) -> Generator[Any, None, None]:
        yield from self._data

    def __reversed__(self) -> Generator[Any, None, None]:
        yield from reversed(self._data)

    def __str__(self) -> str:
        return f"{self.__class__.__name__}({', '.join(map(str, self._data))})"

    def __repr__(self) -> str:
        return f"{self.__class__.__name__}(size={self._size})"

El atributo ._size almacena el tamaño fijo del arreglo o el número de posiciones disponibles, mientras que ._data proporciona un arreglo de bajo nivel creado con ctypes.py_object * size, donde se guardan las referencias a los objetos de Python.

En ._type, se guarda el tipo de dato de los elementos del arreglo. Una vez que asignas el primer valor no nulo, solo se permiten valores de ese mismo tipo.

El método .clear() recorre todas las posiciones del arreglo y les asigna value o None. Si ._type ya está fijado, comprueba que value coincida con ese tipo.

Los métodos especiales te permiten ofrecer las funcionalidades siguientes:

  • .__getitem__(): devuelve el valor almacenado en index después de verificar que el índice esté dentro del rango válido.
  • .__setitem__(): fija el tipo de dato de los elementos del arreglo con el primer value no nulo. A partir de ahí, solo permite valores de ese tipo. También valida que el índice esté en rango antes de asignar.
  • __len__: devuelve el tamaño del arreglo o el número de elementos.
  • __contains__(): comprueba si value está contenido en el arreglo y devuelve True o False.
  • __iter__ y __reversed__: permiten iterar sobre los elementos del arreglo en orden normal o inverso.
  • __str__ y __repr__: devuelven representaciones de cadena que muestran el contenido actual del arreglo.

Ejemplo de uso del arreglo

En esta sección verás ejemplos prácticos de cómo crear, inicializar y manipular instancias de tu clase Array.

Inicialización

Para crear un Array, solo necesitas indicar su tamaño. Todos los elementos se inicializan con None por defecto:

>>> a = Array(5)  # Crea un arreglo con 5 elementos
>>> print(a)
Array(None, None, None, None, None)

Acceso y modificación de elementos

Puedes leer y escribir elementos con el operador de indexado [index], igual que en una lista:

>>> a[0] = 42  # Establece el primer elemento a 42
>>> a[0]
42

Si intentas asignar un valor de un tipo de dato diferente al que ya tiene el arreglo, o usar un índice fuera del rango válido, obtendrás errores claros:

>>> a = Array(3)

>>> a[0] = 1
>>> a[1] = 2

>>> a[2] = "tres"
Traceback (most recent call last):
    ...
TypeError: Expected type <class 'int'>, got <class 'str'>

>>> a[3] = 10
Traceback (most recent call last):
    ...
IndexError: Index out of range: 3. Valid range: 0 to 2

Limpiar el arreglo

El método .clear() restablece todos los elementos asignándoles el valor especificado. El valor predeterminado es None:

>>> a = Array(5)

>>> a.clear(0)  # Establece todos los elementos a 0
>>> print(a)
Array(0, 0, 0, 0, 0)

Longitud y pertenencia

El método .__len__() devuelve el tamaño del arreglo, mientras que .__contains__() verifica si un elemento existe en el arreglo:

>>> a = Array(5)

>>> len(a)
5
>>> 42 in a
False

>>> a[0] = 42
>>> 42 in a
True

Iteración

Los métodos .__iter__() y .__reversed__() permiten iterar sobre el arreglo tanto hacia adelante como hacia atrás:

>>> a = Array(5)
>>> a[0] = 1
>>> a[1] = 2
>>> a[2] = 3
>>> a[3] = 4
>>> a[4] = 5

>>> for item in a:
...     print(item)
...
1
2
3
4
5

>>> for item in reversed(a):
...     print(item)
...
5
4
3
2
1

Representación en cadena

Los métodos .__str__() y .__repr__() son más bien utilitarios y proporcionan representaciones legibles para humanos y amigables para desarrolladores:

>>> a = Array(5)
>>> a.clear(0)

>>> print(a)
Array(0, 0, 0, 0, 0)

>>> print(repr(a))
Array(size=5)

Conclusión

Has aprendido cómo implementar un arreglo de tamaño fijo que proporciona operaciones esenciales como indexación, iteración y pertenencia, al tiempo que refuerza la consistencia del tipo de dato de sus elementos. Este conocimiento te sirve de base para entender estructuras de datos fundamentales en Python.