Python

Equivalencias idiomáticas entre Kotlin y Python. Kotlin se presenta como referencia en cada concepto.

Integración con el ecosistema

Un algoritmo correcto también debe compilarse, organizarse y ejecutarse: estas herramientas son las que hacen posible entregar y comparar una implementación real.

Equivalencia desde Kotlin

Herramientas

Cercana

En Python, uv (uv sync, uv run, pyproject.toml con su lockfile uv.lock) expresa la responsabilidad del fixture: Instala las dependencias declaradas, construye todos los módulos, ejecuta las pruebas y corre la aplicación de línea de comandos.

Referencia Kotlin: Gradle, mediante el wrapper ./gradlew, resuelve las dependencias declaradas, construye los subproyectos registrados en settings.gradle.kts y ejecuta tareas como build, test y :app:run.

Mecanismo
uv (uv sync, uv run, pyproject.toml con su lockfile uv.lock)
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar uv (uv sync, uv run, pyproject.toml con su lockfile uv.lock).
Recomendación
Expón el contrato del fixture y usa uv (uv sync, uv run, pyproject.toml con su lockfile uv.lock) solo para la garantía que realmente ofrece.

Diferencias relevantes

  • Distingue el ejecutable de build invocado (el wrapper o la CLI de la herramienta) de los archivos de manifiesto y lockfile que declaran las dependencias y su resolución.
  • La forma idiomática de Python debe conservarse aunque la sintaxis difiera de Kotlin.

Instala las dependencias declaradas, construye todos los módulos, ejecuta las pruebas y corre la aplicación de línea de comandos.

docker compose run --rm app uv sync
docker compose run --rm app uv run pytest
docker compose run --rm app uv run app

Dockerfile mínimo para el toolchain de Python.

FROM ghcr.io/astral-sh/uv:python3.13-bookworm
WORKDIR /workspace
COPY . .

compose.yaml: construye la imagen y monta el proyecto para correr los comandos anteriores dentro del contenedor.

services:
  app:
    build: .
    volumes:
      - .:/workspace
    working_dir: /workspace

Fuentes

Equivalencia desde Kotlin

Módulos, workspaces y monorepos

Cercana

En Python, un workspace de uv ([tool.uv.workspace] con members = [...] en el pyproject.toml raíz) expresa la responsabilidad del fixture: Organiza un ejecutable de línea de comandos que depende de módulos de dominio reutilizables, conservando el sentido de la dependencia.

Referencia Kotlin: Un build multi-proyecto de Gradle declara sus subproyectos (:app, :optimization:core, :optimization:execution, :optimization:baselines, :optimization:metaheuristics:single-state, :reporting:fair) en settings.gradle.kts mediante include(...), mientras que la lógica de build compartida vive en builds incluidos aparte (build-logic, build-conventions) declarados con includeBuild(...); cada dependencia entre proyectos se declara explícitamente, por ejemplo implementation(projects.optimization.core) en el build.gradle.kts de :app.

Mecanismo
un workspace de uv ([tool.uv.workspace] con members = [...] en el pyproject.toml raíz)
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar un workspace de uv ([tool.uv.workspace] con members = [...] en el pyproject.toml raíz).
Recomendación
Expón el contrato del fixture y usa un workspace de uv ([tool.uv.workspace] con members = [...] en el pyproject.toml raíz) solo para la garantía que realmente ofrece.

Diferencias relevantes

  • Un monorepo es una estrategia de alojamiento de un repositorio, no un mecanismo de build: un repositorio puede ser un monorepo sin usar ningún workspace, y un workspace puede vivir en un repositorio que no aloja ningún otro proyecto además del suyo.
  • La forma idiomática de Python debe conservarse aunque la sintaxis difiera de Kotlin.

Organiza un ejecutable de línea de comandos que depende de módulos de dominio reutilizables, conservando el sentido de la dependencia.

# pyproject.toml (raíz)
[tool.uv.workspace]
members = ["packages/*"]

# packages/cli/pyproject.toml
[project]
dependencies = ["atom-core"]

[tool.uv.sources]
atom-core = { workspace = true }

Fuentes

Equivalencia desde Kotlin

Soporte CLI

Cercana

En Python, Typer, que deriva el análisis desde las anotaciones de tipos de la función de comando expresa la responsabilidad del fixture: Ejecuta random-search con un archivo de configuración y escribe su reporte, mostrando ayuda generada y fallando antes de optimizar ante una opción inválida.

Referencia Kotlin: Clikt define atom como comando raíz sin operación propia (NoOpCliktCommand) con los subcomandos random-search y local-search; cada uno extiende AbstractExperimentCommand, que declara --config y --report como opciones requeridas y --report-format con v4 por defecto, valida la configuración antes de ejecutar el experimento y traduce los errores esperados en CliktError.

Mecanismo
Typer, que deriva el análisis desde las anotaciones de tipos de la función de comando
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar Typer, que deriva el análisis desde las anotaciones de tipos de la función de comando.
Recomendación
Expón el contrato del fixture y usa Typer, que deriva el análisis desde las anotaciones de tipos de la función de comando solo para la garantía que realmente ofrece.

Diferencias relevantes

  • El análisis de argumentos y su validación deben completarse antes de ejecutar cualquier lógica de optimización; ninguna biblioteca madura y con pruebas propias debe reemplazarse por un analizador manual.
  • La forma idiomática de Python debe conservarse aunque la sintaxis difiera de Kotlin.

Ejecuta random-search con un archivo de configuración y escribe su reporte, mostrando ayuda generada y fallando antes de optimizar ante una opción inválida.

@app.command()
def random_search(config: Path, report: Path, report_format: str = "v4") -> None:
    ...  # decodifica, ejecuta y escribe el reporte

Contrato observable compartido por cualquier reimplementación de la CLI.

$ atom random-search --config config.json --report report.json
Completed random-search: 2 runs; report format: v4; report: report.json

Fuentes

Equivalencia desde Kotlin

Serialización

Cercana

En Python, Pydantic (BaseModel, validado en la construcción) expresa la responsabilidad del fixture: Decodifica una configuración JSON con el objetivo, las semillas y el valor objetivo opcional de un experimento, distinguiendo un JSON sintácticamente inválido de un valor de dominio inválido.

Referencia Kotlin: kotlinx.serialization decodifica el JSON tipado mediante un Json compartido (prettyPrint = true, encodeDefaults = true) y un SerializersModule polimórfico para tipos como SearchSpace; readFromJson<T>() decodifica el archivo y deja que SerializationException se propague, mientras que un valor de dominio inválido, como un Delta no positivo, falla por separado en el constructor de su clase de valor.

Mecanismo
Pydantic (BaseModel, validado en la construcción)
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar Pydantic (BaseModel, validado en la construcción).
Recomendación
Expón el contrato del fixture y usa Pydantic (BaseModel, validado en la construcción) solo para la garantía que realmente ofrece.

Diferencias relevantes

  • Un JSON sintácticamente válido puede seguir violando un invariante de dominio; decodificar con éxito no implica que el valor resultante sea válido.
  • La forma idiomática de Python debe conservarse aunque la sintaxis difiera de Kotlin.

Decodifica una configuración JSON con el objetivo, las semillas y el valor objetivo opcional de un experimento, distinguiendo un JSON sintácticamente inválido de un valor de dominio inválido.

class ExperimentConfig(BaseModel):
    objective: str
    seeds: list[int]
    target_value: float = 0.0

config = ExperimentConfig.model_validate_json(json_text)

Payload compartido: seeds es requerido; targetValue es opcional y por defecto 0.0.

{
  "objective": "sphere",
  "seeds": [7, 11],
  "targetValue": 0.0
}

Fuentes

Ecosistemas de pruebas

Verificar el comportamiento de una implementación requiere elegir, entre varias estrategias, la que responde mejor a cada tipo de afirmación sobre el algoritmo.

Equivalencia desde Kotlin

Desarrollo guiado por pruebas (TDD)

Cercana

Formula primero el comportamiento con Given–When–Then. En rojo, ejecuta el test más pequeño que demuestra que falta; en verde, implementa solo lo necesario; al refactorizar, mejora el diseño sin cambiar el comportamiento. Repite el ciclo con la siguiente afirmación. BDD puede ayudar a descubrir o expresar el comportamiento, pero Gherkin y los nombres legibles no son requisitos de TDD.

Referencia Kotlin: TDD parte por una afirmación observable y usa el test para conducir un cambio pequeño.

Mecanismo
pytest con pytest.raises
Riesgo de diseño
Escribir una prueba grande que atraviesa configuración, red o archivos antes de haber fijado una sola regla observable.
Recomendación
Elige una afirmación pequeña, ejecútala en rojo, hazla verde con el cambio mínimo y refactoriza solo mientras permanezca verde.

Diferencias relevantes

  • El ciclo rojo–verde–refactor se conserva entre ecosistemas; cambian el runner, la sintaxis de aserciones y la forma de expresar una excepción.
  • El test debe fallar por el comportamiento ausente, no por una dependencia, una ruta o una integración todavía no necesaria.

Un presupuesto de evaluación positivo se acepta y uno no positivo se rechaza.

import pytest

def test_rejects_a_non_positive_budget():
    with pytest.raises(ValueError):
        Budget(0)

Fuentes

Equivalencia desde Kotlin

Selección de estrategia de pruebas

Cercana

Empieza por la afirmación: usa un ejemplo enfocado para un comportamiento conocido, DDT para una matriz finita y PBT para una ley general. Añade pruebas de componente o integración cuando colaboran módulos, pruebas de contrato para una representación compartida y una verificación de entrega cuando importa el entorno documentado. Para algoritmos estocásticos controla colaboradores, conserva semillas reproducibles y prueba invariantes o evidencia estadística, no una trayectoria casual.

Referencia Kotlin: Seleccionar pruebas parte de la afirmación, la frontera afectada y las dependencias que deben controlarse.

Mecanismo
pytest y sus fixtures para pruebas enfocadas, parametrizadas e integradas
Riesgo de diseño
Usar una prueba end-to-end para demostrar una regla local, o adoptar PBT solo porque hay un generador disponible.
Recomendación
Elige la evidencia más pequeña que pueda observar y falsar la afirmación; amplíala solo cuando una frontera modificada lo requiera.

Diferencias relevantes

  • La selección depende de la afirmación y la frontera, no del lenguaje ni del tamaño de una función.
  • Una prueba más amplia complementa la evidencia enfocada de TDD; no la reemplaza.

La afirmación determina la evidencia más pequeña adecuada antes de ampliar la verificación.

# Regla conocida: un test de pytest.
with pytest.raises(ValueError): Budget(0)
# Matriz finita: @pytest.mark.parametrize.
# Ley general: @given(...) con Hypothesis.

Fuentes

Equivalencia desde Kotlin

Pruebas unitarias

Cercana

En Python, pytest con descubrimiento de test_*.py y pytest.raises expresa la responsabilidad del fixture: Acepta el presupuesto 1000 y rechaza el presupuesto -1 antes de ejecutar optimización.

Referencia Kotlin: Una prueba unitaria llama al analizador de presupuesto y compara el valor o el error de validación.

Mecanismo
pytest con descubrimiento de test_*.py y pytest.raises
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar pytest con descubrimiento de test_*.py y pytest.raises.
Recomendación
Expón el contrato del fixture y usa pytest con descubrimiento de test_*.py y pytest.raises solo para la garantía que realmente ofrece.

Diferencias relevantes

  • La prueba mantiene el análisis local: no inicia una ejecución de optimización ni un proceso externo.
  • La forma idiomática de Python debe conservarse aunque la sintaxis difiera de Kotlin.

Acepta el presupuesto 1000 y rechaza el presupuesto -1 antes de ejecutar optimización.

import pytest

def test_rejects_negative_budget():
    with pytest.raises(ValueError):
        parse_budget("-1")

Fuentes

Equivalencia desde Kotlin

Frameworks y estilos BDD

Cercana

En Python, pytest-bdd sobre la colección y fixtures de pytest expresa la responsabilidad del fixture: Describe que atom random-search --objective sphere --budget 1000 --seed 11 produce una configuración válida sin ejecutar optimización.

Referencia Kotlin: Un escenario describe la configuración observable; analizar el comando no ejecuta el algoritmo.

Mecanismo
pytest-bdd sobre la colección y fixtures de pytest
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar pytest-bdd sobre la colección y fixtures de pytest.
Recomendación
Expón el contrato del fixture y usa pytest-bdd sobre la colección y fixtures de pytest solo para la garantía que realmente ofrece.

Diferencias relevantes

  • BDD comunica comportamiento y colaboración; un nombre de prueba legible por sí solo no crea un flujo de especificación completo.
  • La forma idiomática de Python debe conservarse aunque la sintaxis difiera de Kotlin.

Describe que atom random-search --objective sphere --budget 1000 --seed 11 produce una configuración válida sin ejecutar optimización.

@given(parsers.parse("a budget of {budget:d} evaluations"))
def budget(arguments, budget):
    arguments.extend(["--budget", str(budget)])

@then("a valid experiment configuration is produced")
def valid_configuration(arguments):
    assert parse(arguments).budget == 1000

Fuentes

Equivalencia desde Kotlin

Soporte DDT

Cercana

En Python, @pytest.mark.parametrize expresa la responsabilidad del fixture: Una tabla cubre presupuesto válido, faltante, negativo, objetivo desconocido, semilla repetida y opción desconocida.

Referencia Kotlin: Los casos explícitos vinculan argumentos CLI con un resultado de análisis esperado.

Mecanismo
@pytest.mark.parametrize
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar @pytest.mark.parametrize.
Recomendación
Expón el contrato del fixture y usa @pytest.mark.parametrize solo para la garantía que realmente ofrece.

Diferencias relevantes

  • DDT enumera ejemplos elegidos; no sustituye la generación de dominios ni una especificación de comportamiento.
  • La forma idiomática de Python debe conservarse aunque la sintaxis difiera de Kotlin.

Una tabla cubre presupuesto válido, faltante, negativo, objetivo desconocido, semilla repetida y opción desconocida.

@pytest.mark.parametrize(("value", "valid"), [("1000", True), ("-1", False)])
def test_budget_cases(value, valid):
    assert parse_budget(value).ok is valid

Fuentes

Equivalencia desde Kotlin

Soporte PBT

Cercana

En Python, Hypothesis integrado como decorador de pytest expresa la responsabilidad del fixture: Para cualquier texto decimal positivo aceptado, el presupuesto resultante es positivo; los casos inválidos se reducen y se pueden reproducir.

Referencia Kotlin: Una propiedad general se ejecuta sobre valores generados y comunica cómo repetir un contraejemplo.

Mecanismo
Hypothesis integrado como decorador de pytest
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar Hypothesis integrado como decorador de pytest.
Recomendación
Expón el contrato del fixture y usa Hypothesis integrado como decorador de pytest solo para la garantía que realmente ofrece.

Diferencias relevantes

  • PBT genera y reduce datos; una matriz DDT conserva mejor los ejemplos que el lector debe reconocer directamente.
  • La forma idiomática de Python debe conservarse aunque la sintaxis difiera de Kotlin.

Para cualquier texto decimal positivo aceptado, el presupuesto resultante es positivo; los casos inválidos se reducen y se pueden reproducir.

@given(st.integers(min_value=1))
def test_positive_budgets_remain_positive(budget):
    assert parse_budget(str(budget)).value > 0

Fuentes

Equivalencia desde Kotlin

DSLs de aserciones

Cercana

En Python, assert nativo con introspección reescrita por pytest expresa la responsabilidad del fixture: Una configuración analizada contiene objective = sphere, budget = 1000 y seeds = [11]; una falla debe identificar esperado y recibido.

Referencia Kotlin: Las aserciones expresan el resultado observable de una configuración sin ocultar su estructura relevante.

Mecanismo
assert nativo con introspección reescrita por pytest
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar assert nativo con introspección reescrita por pytest.
Recomendación
Expón el contrato del fixture y usa assert nativo con introspección reescrita por pytest solo para la garantía que realmente ofrece.

Diferencias relevantes

  • Una biblioteca fluida puede mejorar el diagnóstico, pero no reemplaza una expectativa precisa ni es necesaria cuando la API idiomática ya basta.
  • La forma idiomática de Python debe conservarse aunque la sintaxis difiera de Kotlin.

Una configuración analizada contiene objective = sphere, budget = 1000 y seeds = [11]; una falla debe identificar esperado y recibido.

assert config.objective == "sphere"
assert config.budget == 1000
assert config.seeds == [11]

Fuentes