Cómo utilizar goto



Versión: CPython 2.6+, 3.x; PyPy.
Descarga: python-goto.zip.

A diferencia de otros lenguajes, Python no incluye por defecto la funcionalidad goto («ir a», permite realizar saltos a diversas porciones del código), pero dada su flexibilidad, es posible implementar el operador utilizando este módulo.

Se trata de un decorador que emplea los módulos estándar dis y ctypes para reemplazar el byte-code generado por el intérprete e ingresar instrucciones de salto. Opera con las palabras label, para definir una determinada porción del código, y goto, para realizar el salto.

La instalación es sencilla vía python setup.py install o bien copiando manualmente el archivo goto.py en el directorio Python/Lib/.

Introducimos o recordamos (dependiendo de la experiencia del lector) un ejemplo en C utilizando goto, que solicita al usuario ingresar un número. Si se ingresa un valor no permitido (por ejemplo, una letra), se utiliza la instrucción para regresar al comienzo.

int main(int argc, char *argv[])
{
    char input[10];
    int age;

get_input:
    printf("Edad: ");
    fgets(input, 10, stdin);
    age = atoi(input);
    if (age == 0) {
        goto get_input;
    }

    return 0;
}

Salida:

Edad: a
Edad: b
Edad: 5

El código análogo en Python, utilizando el módulo goto:

from goto import with_goto

@with_goto  # Decorador necesario.
def f():
    label .get_input  # Definir porción del código.
    age = raw_input("Edad: ")
    try:
        age = int(age)
    except ValueError:
        goto .get_input  # Regresar a get_input.

f()

¡Nada más sencillo! Si la entrada no puede ser convertida a un número, en la línea número 10 la ejecución regresa a la número 5, etiquetada con el nombre get_input.

Evítese usar las palabras label y goto para nombrar objetos, pues, como comenté anteriormente, son utilizados por el decorador. De lo contrario, se obtiene un error.

...
@with_goto  # Decorador necesario.
def f():
    label = 1
    label .get_input  # Definir porción del código.
...

Traceback (most recent call last):
File "test.py", line 6, in
@with_goto # Decorador necesario.
File ".../goto.py", line 114, in with_goto
_patch_code(func_or_code.__code__),
File ".../goto.py", line 88, in _patch_code
raise SyntaxError('Unknown label %r' % code.co_names[arg])
SyntaxError: Unknown label 'get_input'

Otros ejemplos:

@with_goto
def range(start, stop):
    i = start
    result = []

    label .begin
    if i == stop:
        goto .end

    result.append(i)
    i += 1
    goto .begin

    label .end
    return result

Puedes conocer más sobre la implementación interna del módulo en el proyecto en GitHub.

Al margen, como alusión a las buenas prácticas, me permito recordarte que ¡todo lo que puedes hacer utilizando goto puede ser implementado de una forma más bonita y eficiente sin necesidad de recurrir a módulos de terceros!



Deja un comentario