5 - Operaciones fundamentales de una pila con listas

API esencial con Python

Una vez definida la estructura base (lista como buffer y tope al final), las operaciones de la pila deben ser deterministas y constantes. Las siguientes secciones muestran el esqueleto de una clase PilaLista centrada en enteros, pero las mismas rutinas funcionan con cualquier tipo de dato.

class PilaLista:
  def __init__(self, capacidad=None):
    self._datos = []
    self._capacidad = capacidad

  def __len__(self):
    return len(self._datos)

  def esta_vacia(self):
    return len(self._datos) == 0

5.1 Push (apilar)

Inserta un elemento en el tope si existe espacio disponible. Se recomienda validar la capacidad antes de mutar el buffer.

  def push(self, valor):
    if self._capacidad is not None and len(self._datos) >= self._capacidad:
      raise OverflowError("Pila llena")
    self._datos.append(valor)

5.2 Pop (desapilar)

Remueve y devuelve el elemento superior. Debe protegerse contra el underflow lanzando IndexError cuando la pila está vacía.

  def pop(self):
    if self.esta_vacia():
      raise IndexError("Pila vacia")
    return self._datos.pop()

5.3 Peek (ver el tope sin quitarlo)

Permite consultar el valor en el tope sin modificar el estado interno. Resulta clave en parsers o validaciones previas.

  def peek(self):
    if self.esta_vacia():
      raise IndexError("Pila vacia")
    return self._datos[-1]

5.4 Consultas de estado

Para evitar cálculos repetidos, conviene exponer funciones auxiliares que documenten las precondiciones de la API.

  def esta_llena(self):
    if self._capacidad is None:
      return False
    return len(self._datos) >= self._capacidad

  def limpiar(self):
    self._datos.clear()

La función esta_llena simplifica la construcción de interfaces de usuario: se puede deshabilitar un botón de push si ya no hay espacio.

5.5 Impresión para depurar

Recorrer la pila desde el tope hacia la base es útil para inspeccionar el estado durante ejercicios o debugging.

  def imprimir(self):
    print(f"Pila ({len(self)} elementos):")
    for i, valor in enumerate(reversed(self._datos)):
      marca = "<- top" if i == 0 else ""
      print(f"  {valor} {marca}")

La inversión con reversed mantiene el orden LIFO sin modificar la lista original.

Código completo y prueba rápida

Integrando todas las piezas, obtenemos una pila lista para usarse en cualquier script o cuaderno interactivo:

class PilaLista:
  def __init__(self, capacidad=None):
    self._datos = []
    self._capacidad = capacidad

  def __len__(self):
    return len(self._datos)

  def esta_vacia(self):
    return len(self._datos) == 0

  def esta_llena(self):
    return self._capacidad is not None and len(self._datos) >= self._capacidad

  def push(self, valor):
    if self.esta_llena():
      raise OverflowError("Pila llena")
    self._datos.append(valor)

  def pop(self):
    if self.esta_vacia():
      raise IndexError("Pila vacia")
    return self._datos.pop()

  def peek(self):
    if self.esta_vacia():
      raise IndexError("Pila vacia")
    return self._datos[-1]

  def imprimir(self):
    print(f"Pila ({len(self)} elementos):")
    for i, valor in enumerate(reversed(self._datos)):
      print(f"  {valor}{' <- top' if i == 0 else ''}")


if __name__ == "__main__":
  pila = PilaLista(capacidad=4)

  for n in (10, 20, 30):
    pila.push(n)
  pila.imprimir()

  print("Peek:", pila.peek())

  while not pila.esta_vacia():
    print("Pop:", pila.pop())

Ejecuta el script con python tema5_demo.py o pruébalo directamente en el editor online: