`goto` in Python

Albert picture Albert · Aug 5, 2011 · Viewed 21.9k times · Source

I must use goto in Python. I found entrians goto but my Python implementation (CPython 2.7.1 on Mac) does not have this module, so it doesn't seem to be portable. It should at least work in all Python implementations which support CPython bytecode (esp. I care about CPython and PyPy). Then there is this related question, and cdjc's goto. And the ones given by answers below.

I could go and build up the bytecode manually (i.e. write my own Python compiler) because there is such an instruction (JUMP_ABSOLUTE and friends). But I wonder if there is an easier way. Is it possible via inspect or so to call a single bytecode instruction? I also thought about compiling via Python and then automatically patching the generated Python bytecode.


Of course, people will ask why and will not give me any helpful answer if I don't explain why I really really need this. So in short my use case: I am translating a C AST to Python AST and compiling this. I can map every logical flow (all the loops and other stuff) in some way to equivalent Python code. Everything except goto. Related projects: PyCParser (see interpreter.py), PyCPython, PyLua.

Answer

Paolo Moretti picture Paolo Moretti · Aug 5, 2011

I know what everybody is thinking:

xkcd GOTO

However, there might be some didactic cases where you actually need a goto.

This python recipe provides the goto command as a function decorator.

The goto decorator (Python recipe by Carl Cerecke)

This is the recipe for you if you are sick of the slow speed of the existing goto module http://entrian.com/goto/. The goto in this recipe is about 60x faster and is also cleaner (abusing sys.settrace seems hardly pythonic). Because this is a decorator, it alerts the reader which functions use goto. It does not implement the comefrom command, although it is not difficult to extend it to do so (exercise for the reader). Also, computed gotos aren't supported; they're not pythonic.

  • Use dis.dis(fn) to show the bytecode disassembly of a function.
  • The bytecodes of a function are accessed by fn.func_code.co_code. This is readonly so:
  • The decorated function is created exactly the same as the old one, but with the bytecode updated to obey the goto commands.
  • This is 2.x only; the new module is not in python 3.x (another exercise for the reader!)

Usage

@goto
def test1(n):
    s = 0

    label .myLoop

    if n <= 0:
        return s
    s += n
    n -= 1

    goto .myLoop

>>> test1(10)
55

Update

Here're two additional implementations compatible with Python 3: