`goto` in Python
I know what everybody is thinking:
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/. Thegoto
in this recipe is about 60x faster and is also cleaner (abusingsys.settrace
seems hardly pythonic). Because this is a decorator, it alerts the reader which functions usegoto
. 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
@gotodef 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:
You may have the only valid use case I have ever seen for needing goto
in Python. :-)
The most straightforward way to emulate forward goto
in Python is using exceptions, as these can jump out of any depth of nested control structures.
class Goto(Exception): passtry: if foo = "bar": raise Goto print "foo is not bar"except Goto: print "foo is bar"
This gets hairy if you need to support more than one destination, but I think it could be done using nested try/except
structures and multiple classes of exception, one for each destination. Since C limits goto
to the scope of a single function, at least you won't have to worry about how to make this work across functions. :-) Of course, it doesn't work for reverse goto
s.
Another thing to note is that exceptions in Python, while fast compared to some languages, are still slower than normal flow control structures such as while
and for
.
This could be a lot of work (though perhaps not more than you're already in for), but if you could generate Python bytecode rather than Python source, you would have no problem implementing goto
, because Python bytecode (like most psuedo-machine-languages) has a perfectly cromulent JUMP_ABSOLUTE
opcode.
I've updated my python goto decorator for Python 3. You can get it at https://github.com/cdjc/goto. Using goto instead of functions can make a state machine about 5 times faster.
The version for python 2 is still available at http://code.activestate.com/recipes/576944-the-goto-decorator/ but it has a number of bugs that are fixed in the python 3 version.