Successfully reported this slideshow.
Upcoming SlideShare
×

# TCO in Python via bytecode manipulation.

1,026 views

Published on

TCO in Python via bytecode manipulation.

Published in: Software
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

### TCO in Python via bytecode manipulation.

1. 1. Optimizing tail recursion in Python using bytecode manipulations. Allison Kaptur Paul Tagliamonte Liuda Nikolaeva (all errors are my own)
2. 2. Problem: Python has a limit on recursion depth: def factorial(n, accum): if n <= 1: return accum else: return factorial(n-1, accum*n) >>> tail-factorial(1000) RuntimeError: maximum recursion depth exceeded
3. 3. Challenge: • Optimize recursive function calls so that they don’t create new frames, thus avoiding stack overflow. • What we want: eliminate the recursive call; instead, reset the variables and jump to the beginning of the function.
4. 4. Problem: How do you change the insides of a function?
5. 5. Bytecode! Solution: (obviously)
6. 6. Quick intro to bytecode. def f(n, accum): if n <= 1: return accum else: return f(n-1, accum*n) >>> f.__code__.co_code '|x00x00dx01x00kx01x00rx10x00|x01x00Stx00x00|x00 x00dx01x00x18|x01x00|x00x00x14x83x02x00Sdx00x00 S‘ >>> print [ord(b) for b in f.__code__.co_code] [124, 0, 0, 100, 1, 0, 107, 1, 0, 114, 16, 0, 124, 1, 0, 83, 116, 0, 0, 124, 0, 0, 100, 1, 0, 24, 124, 1, 0, 124, 0, 0, 20, 131, 2, 0, 83, 100, 0, 0, 83]
7. 7. def f(n, accum): if n <= 1: return accum else: return f(n-1, accum*n) >>> import dis >>> dis.dis(f) 2 0 LOAD_FAST 0 (n) 3 LOAD_CONST 1 (1) 6 COMPARE_OP 1 (<=) 9 POP_JUMP_IF_FALSE 16 3 12 LOAD_FAST 1 (accum) 15 RETURN_VALUE 5 >> 16 LOAD_GLOBAL 0 (f) 19 LOAD_FAST 0 (n) 22 LOAD_CONST 1 (1) 25 BINARY_SUBTRACT 26 LOAD_FAST 1 (accum) 29 LOAD_FAST 0 (n) 32 BINARY_MULTIPLY 33 CALL_FUNCTION 2 36 RETURN_VALUE 37 LOAD_CONST 0 (None) 40 RETURN_VALUE
8. 8. def f(n, accum): if n <= 1: return accum else: return f(n-1, accum*n) >>> import dis >>> dis.dis(f) 2 0 LOAD_FAST 0 (n) 3 LOAD_CONST 1 (1) 6 COMPARE_OP 1 (<=) 9 POP_JUMP_IF_FALSE 16 3 12 LOAD_FAST 1 (accum) 15 RETURN_VALUE 5 >> 16 LOAD_GLOBAL 0 (f) 19 LOAD_FAST 0 (n) 22 LOAD_CONST 1 (1) 25 BINARY_SUBTRACT 26 LOAD_FAST 1 (accum) 29 LOAD_FAST 0 (n) 32 BINARY_MULTIPLY 33 CALL_FUNCTION 2 36 RETURN_VALUE 37 LOAD_CONST 0 (None) 40 RETURN_VALUE
9. 9. def f(n, accum): if n <= 1: return accum else: return f(n-1, accum*n) >>> import dis >>> dis.dis(f) 2 0 LOAD_FAST 0 (n) 3 LOAD_CONST 1 (1) 6 COMPARE_OP 1 (<=) 9 POP_JUMP_IF_FALSE 16 3 12 LOAD_FAST 1 (accum) 15 RETURN_VALUE 5 >> 16 LOAD_GLOBAL 0 (f) 19 LOAD_FAST 0 (n) 22 LOAD_CONST 1 (1) 25 BINARY_SUBTRACT 26 LOAD_FAST 1 (accum) 29 LOAD_FAST 0 (n) 32 BINARY_MULTIPLY 33 CALL_FUNCTION 2 36 RETURN_VALUE 37 LOAD_CONST 0 (None) 40 RETURN_VALUE