Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/snoack/python-goto
A function decorator, that rewrites the bytecode, to enable goto in Python
https://github.com/snoack/python-goto
Last synced: 30 days ago
JSON representation
A function decorator, that rewrites the bytecode, to enable goto in Python
- Host: GitHub
- URL: https://github.com/snoack/python-goto
- Owner: snoack
- License: unlicense
- Created: 2015-09-18T12:27:32.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2021-02-27T23:01:11.000Z (almost 4 years ago)
- Last Synced: 2024-11-01T00:47:22.409Z (about 1 month ago)
- Language: Python
- Homepage:
- Size: 37.1 KB
- Stars: 1,279
- Watchers: 23
- Forks: 87
- Open Issues: 15
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-python-decorator - python-goto
README
# goto
[![Build Status](https://travis-ci.org/snoack/python-goto.svg?branch=master)](https://travis-ci.org/snoack/python-goto)
[![Pypi Entry](https://badge.fury.io/py/goto-statement.svg)](https://pypi.python.org/pypi/goto-statement)A function decorator to use `goto` in Python.
Tested on Python 2.6 through 3.7 and PyPy.[![](https://imgs.xkcd.com/comics/goto.png)](https://xkcd.com/292/)
## Installation
```
pip install goto-statement
```## Usage
```python
from goto import with_goto@with_goto
def range(start, stop):
i = start
result = []label .begin
if i == stop:
goto .endresult.append(i)
i += 1
goto .beginlabel .end
return result
```## Implementation
Note that `label .begin` and `goto .begin` is regular Python syntax to retrieve
the attribute `begin` from the objects with the variable names `label` and
`goto`. However, in the example above these variables aren't defined.
So this code would usually cause a `NameError`. But since it's valid
syntax the function can be parsed, and results in following bytecode:```
5 0 LOAD_FAST 0 (start)
2 STORE_FAST 2 (i)6 4 BUILD_LIST 0
6 STORE_FAST 3 (result)8 8 LOAD_GLOBAL 0 (label)
10 LOAD_ATTR 1 (begin)
12 POP_TOP9 14 LOAD_FAST 2 (i)
16 LOAD_FAST 1 (stop)
18 COMPARE_OP 2 (==)
20 POP_JUMP_IF_FALSE 2810 22 LOAD_GLOBAL 2 (goto)
24 LOAD_ATTR 3 (end)
26 POP_TOP12 >> 28 LOAD_FAST 3 (result)
30 LOAD_METHOD 4 (append)
32 LOAD_FAST 2 (i)
34 CALL_METHOD 1
36 POP_TOP13 38 LOAD_FAST 2 (i)
40 LOAD_CONST 1 (1)
42 INPLACE_ADD
44 STORE_FAST 2 (i)14 46 LOAD_GLOBAL 2 (goto)
48 LOAD_ATTR 1 (begin)
50 POP_TOP16 52 LOAD_GLOBAL 0 (label)
54 LOAD_ATTR 3 (end)
56 POP_TOP17 58 LOAD_FAST 3 (result)
60 RETURN_VALUE
```The `with_goto` decorator then removes the respective bytecode that has been
generated for the attribute lookups of the `label` and `goto` variables, and
injects a `JUMP_ABSOLUTE` or `JUMP_RELATIVE` instruction for each `goto`:```
5 0 LOAD_FAST 0 (start)
2 STORE_FAST 2 (i)6 4 BUILD_LIST 0
6 STORE_FAST 3 (result)8 8 NOP
10 NOP
12 NOP9 >> 14 LOAD_FAST 2 (i)
16 LOAD_FAST 1 (stop)
18 COMPARE_OP 2 (==)
20 POP_JUMP_IF_FALSE 2810 22 JUMP_FORWARD 34 (to 58)
24 NOP
26 NOP12 >> 28 LOAD_FAST 3 (result)
30 LOAD_METHOD 4 (append)
32 LOAD_FAST 2 (i)
34 CALL_METHOD 1
36 POP_TOP13 38 LOAD_FAST 2 (i)
40 LOAD_CONST 1 (1)
42 INPLACE_ADD
44 STORE_FAST 2 (i)14 46 JUMP_ABSOLUTE 14
48 NOP
50 NOP16 52 NOP
54 NOP
56 NOP17 >> 58 LOAD_FAST 3 (result)
60 RETURN_VALUE
```## Alternative implementation
The idea of `goto` in Python isn't new.
There is [another module](http://entrian.com/goto/) that has been released
as April Fool's joke in 2004. That implementation doesn't touch the bytecode,
but uses a trace function, similar to how debuggers are written.While this eliminates the need for a decorator, it comes with significant
runtime overhead and a more elaborate implementation. Modifying the bytecode,
on the other hand, is fairly simple and doesn't add overhead at function
execution.