Los tres lenguajes tienen for, pero cada uno lo entiende a su manera. Java tiene dos formas, Go usa una sola palabra para todos los bucles, y en Python el for siempre recorre algo. Los comparamos con ejemplos ejecutados en los tres.
public class CicloFor {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
System.out.println("valor de i: " + i);
}
String[] lenguajes = {"Java", "Go", "Python"};
for (String l : lenguajes) {
System.out.println(l);
}
for (int i = 0, j = 10; i < j; i += 3, j -= 3) {
System.out.println(i + " " + j);
}
}
}
java CicloFor.javavalor de i: 0
valor de i: 1
valor de i: 2
Java
Go
Python
0 10
3 7
El primero es el for heredado de C: una inicialización, una condición que se comprueba antes de cada vuelta y un incremento que se ejecuta al final de cada una. El segundo, el «for mejorado», recorre un arreglo o cualquier colección sin índice. El tercero recuerda que cada una de las tres partes puede tener varias expresiones separadas por comas.
Go: una sola palabra para todos los bucles
package main
import "fmt"
func main() {
for i := 0; i < 3; i++ {
fmt.Println("valor de i: ", i)
}
for i := range 3 {
fmt.Println("range:", i)
}
lenguajes := []string{"Java", "Go", "Python"}
for i, l := range lenguajes {
fmt.Println(i, l)
}
n := 1
for n < 100 {
n *= 3
}
fmt.Println("primera potencia de 3 mayor que 100:", n)
for {
fmt.Println("una vez y fuera")
break
}
}
go run .valor de i: 0
valor de i: 1
valor de i: 2
range: 0
range: 1
range: 2
0 Java
1 Go
2 Python
primera potencia de 3 mayor que 100: 243
una vez y fuera
Go no tiene while ni do: todo se escribe con for. Con tres partes es el clásico, sin paréntesis. Con solo la condición, hace de while. Sin nada es un bucle infinito, del que se sale con break. Y con range recorre colecciones devolviendo el índice y el valor. Desde Go 1.22, range también acepta un número: for i := range 3 da 0, 1 y 2.
Fíjate en los dos espacios de valor de i: 0. fmt.Println pone un espacio entre cada argumento, y el texto ya terminaba en espacio. En Go se escribe fmt.Println("valor de i:", i), sin el espacio final.
Python: siempre recorre algo
for i in range(3):
print("valor de i: ", i)
for i in range(3):
print("valor de i:", i)
lenguajes = ["Java", "Go", "Python"]
for i, l in enumerate(lenguajes):
print(i, l)
for i in range(10, 0, -3):
print(i, end=" ")
print()
for l in lenguajes:
if l == "Rust":
break
else:
print("no había Rust")
python ciclo.pyvalor de i: 0
valor de i: 1
valor de i: 2
valor de i: 0
valor de i: 1
valor de i: 2
0 Java
1 Go
2 Python
10 7 4 1
no había Rust
En Python no hay for con contador: se recorre una secuencia, y range genera los números. range(10, 0, -3) cuenta hacia atrás de tres en tres, y enumerate da el índice junto a cada elemento. El primer print tiene el mismo doble espacio que Go, por el mismo motivo: print separa sus argumentos con un espacio.
Lo exclusivo de Python es el else del for: se ejecuta solo si el bucle terminó sin break. Sirve para búsquedas como esta, donde llegar al final significa que no se encontró nada.
Lado a lado
Java
Go
Python
Contar de 0 a 9
for (int i = 0; i < 10; i++)
for i := 0; i < 10; i++ o for i := range 10
for i in range(10):
Recorrer una colección
for (String l : lista)
for _, l := range lista
for l in lista:
Con índice
el for clásico
for i, l := range lista
for i, l in enumerate(lista):
Mientras se cumpla algo
while (cond)
for cond
while cond:
Infinito
while (true)
for
while True:
Bloque
llaves
llaves, obligatorias
sangría
Lo que cambia por debajo
La versión anterior de esta entrada decía que Java es un lenguaje interpretado, como Python. No es exacto, y la diferencia explica buena parte de la diferencia de velocidad. Java se compila a bytecode, y la máquina virtual compila a código máquina, mientras el programa se ejecuta, las partes que más se usan. Go se compila directamente a un ejecutable nativo. Python, en su implementación habitual, también compila a bytecode, pero lo interpreta instrucción a instrucción, y por eso un bucle con mucho cálculo suele ir bastante más despacio. Para medirlo bien, mira medir el rendimiento en Java.
Entrada publicada en 2020 y revisada en octubre de 2026. Cada ejemplo se ejecutó en un contenedor limpio con Java 25 LTS, Go 1.25 y Python 3.14; las salidas están copiadas de esa ejecución.
Python trae mucho de serie, pero buena parte de lo que se hace con él a diario se apoya en librerías externas. Estas son las que más se usan, agrupadas por tarea y cada una con un ejemplo corto que puedes copiar y ejecutar.
Ten en cuenta que el nombre del paquete no siempre coincide con el del import: se instala pillow y se importa PIL, se instala beautifulsoup4 y se importa bs4.
Para…
Librería
Versión probada
Peticiones HTTP
requests
2.34.2
Barras de progreso
tqdm
4.70.1
Imágenes
Pillow
12.3.0
Cálculo numérico
NumPy
2.5.3
Tablas de datos
pandas
3.0.6
Gráficas
Matplotlib
3.11.2
Extraer datos de HTML
Beautiful Soup
4.15.0
Bases de datos
SQLAlchemy
2.1.4
APIs web
FastAPI
0.143.0
Pruebas
pytest
9.1.1
requests: peticiones HTTP
import requests
r = requests.get("https://httpbin.org/get", params={"lenguaje": "python"}, timeout=10)
print(r.status_code, r.headers["Content-Type"])
print(r.json()["args"])
r = requests.post("https://httpbin.org/post", json={"sitio": "decodigo.com"}, timeout=10)
print(r.json()["json"])
Con params se arma la cadena de consulta, con json= se envía un cuerpo JSON con su cabecera, y r.json() decodifica la respuesta. Pon siempre un timeout: sin él, una petición a un servidor que no responde puede quedarse esperando indefinidamente. Si solo necesitas algo puntual y no quieres dependencias, la biblioteca estándar también lo hace; lo vemos en peticiones HTTP sin dependencias.
tqdm: barras de progreso
from time import sleep
from tqdm import tqdm
total = 0
for n in tqdm(range(50), desc="Procesando", ncols=70):
total += n
sleep(0.02)
print("suma:", total)
salida, última línea de la barraProcesando: 100%|█████████████████████| 50/50 [00:01<00:00, 49.11it/s]
suma: 1225
Basta con envolver el iterable en tqdm(). La barra se va redibujando en la misma línea y muestra el avance, la velocidad y el tiempo que falta. Es muy útil en procesos largos, porque deja ver enseguida si el trabajo avanza o se ha atascado.
thumbnail reduce la imagen para que quepa en la caja que le das (200×200), pero conserva la proporción: por eso queda en 200×100 y no se deforma. Pillow abre y guarda los formatos habituales (PNG, JPEG, WebP, GIF…) y sirve para recortar, rotar, dibujar o cambiar el formato por lotes.
salidamedia: 21.14 máxima: 24.3
[65.3 69.8 75.74 67.64 71.78]
count sum mean
lenguaje
Python 3 400 133.333333
Java 2 175 87.500000
Go 1 40 40.000000
NumPy opera sobre arreglos completos de una vez: temps * 9 / 5 + 32 convierte las cinco temperaturas sin escribir ningún bucle, y además mucho más rápido que un bucle en Python. pandas se apoya en NumPy para trabajar con tablas: aquí agrupa por lenguaje y calcula el número de filas, la suma y la media de cada grupo en una sola línea. Si trabajas con archivos muy grandes, merece la pena mirar también Polars, una alternativa más reciente y muy rápida.
La gráfica que genera el ejemplo, tal cual. Los datos son inventados.
matplotlib.use("Agg") hace que dibuje directamente a un archivo, sin abrir ninguna ventana; así funciona también en un servidor o en un contenedor. En tu ordenador puedes quitarlo y llamar a plt.show() para ver la gráfica en pantalla.
Beautiful Soup: extraer datos de HTML
from bs4 import BeautifulSoup
html = """
<ul id="lenguajes">
<li class="activo"><a href="/python">Python</a></li>
<li><a href="/java">Java</a></li>
<li class="activo"><a href="/rust">Rust</a></li>
</ul>
"""
soup = BeautifulSoup(html, "html.parser")
for a in soup.select("#lenguajes li.activo a"):
print(a.text, "->", a["href"])
salidaPython -> /python
Rust -> /rust
select acepta selectores CSS, los mismos que se usan en las hojas de estilo, así que #lenguajes li.activo a se lee igual que en CSS. Para descargar la página se combina con requests. Si lo que necesitas es recorrer un sitio entero siguiendo enlaces, la herramienta adecuada es Scrapy. Y antes de extraer datos de un sitio, revisa sus condiciones de uso y su robots.txt.
SQLAlchemy: bases de datos
from sqlalchemy import create_engine, select, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class Articulo(Base):
__tablename__ = "articulos"
id: Mapped[int] = mapped_column(primary_key=True)
titulo: Mapped[str] = mapped_column(String(100))
visitas: Mapped[int]
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
with Session(engine) as s:
s.add_all([Articulo(titulo="Hola mundo", visitas=10),
Articulo(titulo="Leer CSV", visitas=42),
Articulo(titulo="Peticiones HTTP", visitas=27)])
s.commit()
consulta = select(Articulo).where(Articulo.visitas > 20).order_by(Articulo.visitas.desc())
for a in s.scalars(consulta):
print(a.titulo, a.visitas)
salidaLeer CSV 42
Peticiones HTTP 27
Cada tabla se define como una clase, y las consultas se escriben en Python en lugar de en SQL. Es el estilo de SQLAlchemy 2, con anotaciones de tipo (Mapped[int]). El mismo código funciona con SQLite, PostgreSQL o MySQL cambiando solo la cadena de conexión. Para SQLite sin ninguna librería externa, mira SQLite con Python.
FastAPI: APIs web
from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel
app = FastAPI()
class Articulo(BaseModel):
titulo: str
visitas: int = 0
@app.get("/saludo/{nombre}")
def saludo(nombre: str):
return {"mensaje": f"Hola, {nombre}"}
@app.post("/articulos")
def crear(articulo: Articulo):
return {"creado": articulo.titulo, "visitas": articulo.visitas}
cliente = TestClient(app)
print(cliente.get("/saludo/Ana").json())
print(cliente.post("/articulos", json={"titulo": "FastAPI"}).json())
r = cliente.post("/articulos", json={"visitas": "muchas"})
print(r.status_code, [e["loc"][-1] + ": " + e["type"] for e in r.json()["detail"]])
FastAPI usa las anotaciones de tipo para validar lo que llega: en la última petición falta el título y visitas no es un número, así que responde con un error 422 que explica cada fallo, sin que hayas escrito ninguna validación. Aquí se prueba con TestClient, que llama a la API sin levantar un servidor; en producción se ejecuta con uvicorn.
Con las versiones actuales, TestClient avisa de que usar httpx está obsoleto y pide instalar httpx2. Por eso aparece en el pip install de arriba; con él, el aviso desaparece y el ejemplo funciona igual.
Si buscas un framework completo, con panel de administración, usuarios y plantillas incluidos, la referencia es Django. Para algo pequeño y sin estructura impuesta, Flask.
Las pruebas son funciones que empiezan por test_ y usan un assert normal. parametrize ejecuta la misma prueba con varios casos, y cada uno aparece por separado en el informe; pytest.raises comprueba que se lanza la excepción esperada.
Interfaces gráficas multiplataforma, también para móviles
La versión de 2019 de esta entrada incluía Twisted, un framework de red basado en eventos. Sigue existiendo, pero hoy, para la mayoría de los programas concurrentes, se usa asyncio, que viene con Python, o librerías construidas sobre él.
Entrada publicada en 2019 y revisada en octubre de 2026. Todo el código se ejecutó con Python 3.14.8 en un contenedor limpio, con las versiones de la tabla; las salidas están copiadas de esa ejecución.