¿Y si Python permitiera 'end' como fin de bloque? II
Tags: spanish, python, code, discuss
Published: 2024-02-10 20:44:27

---
title: ¿Y si Python permitiera 'end' como fin de bloque? II
published: true
series: ¿Python con 'end' para fin de bloque?
description: Al final propuse la idea en el foro de los desarrolladores...
tags: #spanish #python #code #discuss
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2024-02-10 18:33 +0000
---

Hace unos días, [pensé en una propuesta](https://dev.to/baltasarq/y-si-python-permitiera-end-como-fin-de-bloque-3p5f) que, según yo mismo, mejoraría la legibilidad del código fuente en Python.

Al final, examiné las normas de propuestas de cambios para Python. Lo primero que se me vino a la cabeza fueron los PEP (Propuestas de mejora de Python o *Python Enhance Proposals*), pero el paso previo era discutir la cuestión primero en [discuss.python.org](http://discuss.python.org/), sección **ideas**.

Dicho y hecho, [propuse la idea en el foro](https://discuss.python.org/t/suggestion-add-end-as-a-keyword-for-marking-end-of-blocks/), y, como quien dice, me senté a esperar los resultados.

Recordemos el ejemplo de código.

```python
i = 0
while < 100:
    if i % 2 == 0:
        i *= 2
        print(i)

    i += 1
```

Al no haber marcas de fin de bloque más allá de la indentación, se pierde legibilidad. Por ejemplo, en este código la instrucción `i += 1` parece como que "cuelga" por su cuenta.

A ver, lo cierto es solo tenía una vaga esperanza de que la idea tuviera tracción (los *pythonistas* son muy suyos), y así fue, la mayor parte de las respuestas son más del tipo *troll* que otra cosa.

Pero sí hubo algunas propuestas interesantes. ¡Analicémoslas!

- Utilizar `# end`. En mi ejemplo, proponía el uso de una palabra clave **end**, diciendo que en este momento no se soportaba a no ser que se transformase en un comentario. Una propuesta es hacer justo eso:

```python
i = 0
while < 100:
    if i % 2 == 0:
        i *= 2
        print(i)
    # end

    i += 1
# end
```

No hay compromisos, es decir, adoptar este estilo de código fuente no afectaría en nada al compilador (ni siquiera habría que modificarlo), ni al código generado (que no cambia en nada). El *nuevo estilo* es optativo, evidentemente, pues de todas formas no podríamos forzar un nuevo estilo en un lenguaje de programación tan maduro como Python.

- Utilizar `...` o `pass` en el lugar de `end`. Todos conocemos `pass` como una palabra clave que permite crear un bloque de código sin contenido real. Una nueva versión de `pass` es `...` (ambas son versiones de la clase **Elipsis**). Podemos utilizarlos en el lugar del `end` deseado.

```python
i = 0
while < 100:
    if i % 2 == 0:
        i *= 2
        print(i)
    ...

    i += 1
...
```

Lo cierto es que funciona sin problema, al igual que la propuesta anterior del comentario, pero no es muy *idiomático*.

- Utilizar una constante `end` como una expresión libre, es decir, sin uso. Esta propuesta quedaría así:

```python
end = "end"

i = 0
while < 100:
    if i % 2 == 0:
        i *= 2
        print(i)
    end

    i += 1
end
```

Esta solución es ingeniosa, y aparentemente consigue solucionar todos los posibles problemas vistos hasta ahora. El problema... el problema es que genera código, a pesar de que la expresión no se utiliza en absoluto. Esto podemos comprobarlo con `dis`, el módulo desensamblador de la librería estándar de Python.

```python
import dis

dis.dis("""
end = "end"

i = 0
while < 100:
    if i % 2 == 0:
        i *= 2
        print(i)
    end

    i += 1
end
""")
<...>
                LOAD_GLOBAL              4 (end)
             96 POP_TOP
             98 JUMP_BACKWARD           34 (to 32)
```

Python utiliza una máquina virtual basada en una pila. Por ejemplo, para sumar dos números `a` y `b` metería (*push*, o *load*), primero `a`, después `b`, y después ejecutaría el `operador +`, que tomaría sus dos parámetros sacándolos (*pop*) de la pila. En el ejemplo de arriba, vemos como mete en la pila `end`, para inmediatamente ejecutar `POP_TOP`, es decir, eliminar el tope de la pila. Aunque el código a ejecutar es mínimo y probablemente resulte eliminado por la máquina virtual durante la ejecución, no tiene mucho sentido que un mecanismo de estilo modifique el código a ejecutar.

- Mezclar las dos propuestas anteriores. Es decir, ya que es posible crear constantes como `end`, en lugar de hacerla valer una cadena de caracteres sin interés, hacerla valer directamente la elipsis. Esto haría ver al compilador, al contener la constante una elipsis, que no requiere generar código para ella.

```python
end = ...

i = 0
while < 100:
    if i % 2 == 0:
        i *= 2
        print(i)
    end

    i += 1
end
```

El problema es que... sucede exactamente lo mismo que en la versión anterior. Es decir, a pesar de que la constante `end` alberga la elipsis, el compilador no es capaz de darse cuenta de que no debería generar código, primero porque va a generar un LOAD inmediatamente seguido de un POP_TOP, y segundo porque el contenido de la constante es la elipsis, que ahí sí ya es seguro que no va a generar nada útil.

Así que, finalmente, las dos posibilidades más realistas son utilizar `# end` o `...`. Todas las posibilidades basadas en una constante funcionan, pero modifican el código generado, algo que no deseamos. La mejor opción sería crear no una constante (que al fin y al cabo, no deja de ser en realidad una variable global), sino algún tipo de alias o de macrosustitución, algo que no es soportado en Python.

¿Alguna idea? ¡Pónmelo en los comentarios!