-
-
Save progval/ee62e41157d8e906d3ae46a3bf2577ba to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import array | |
import functools | |
import types | |
# reuse the bytecode magic from | |
# https://github.com/snoack/python-goto/blob/master/goto.py | |
# Install with `pip3 install goto-statement` | |
import goto | |
def _make_code(code, codestring, co_names): | |
return code.replace(co_code=codestring) | |
def _patch_code(code): | |
concatenator_name_index = len(code.co_names) | |
co_names = code.co_names + ("concatenator",) | |
instructions = list(goto._parse_instructions(code.co_code)) | |
buf = array.array('B', code.co_code) | |
i = -1 | |
while i+2 < len(instructions): | |
i += 1 | |
inst = instructions[i] | |
if inst[0] not in ("BUILD_LIST", "LIST_EXTEND"): | |
# BUILD_LIST for py < 3.9, LIST_EXTEND for py >= 3.9 | |
continue | |
if instructions[i+1][0] != "LOAD_CONST": | |
continue | |
if instructions[i+2][0] != "BINARY_SUBSCR": | |
continue | |
const_idx = instructions[i+1][1] | |
const = code.co_consts[const_idx] | |
if isinstance(const, tuple): | |
# py >= 3.9 only | |
goto._write_instruction(buf, instructions[i+2][2], "LIST_EXTEND", 1) | |
else: | |
goto._write_instruction(buf, instructions[i+2][2], "LIST_APPEND", 1) | |
i += 2 | |
return _make_code(code, buf.tobytes(), co_names) | |
def with_list_concat(func_or_code): | |
if isinstance(func_or_code, types.CodeType): | |
return _patch_code(func_or_code) | |
return functools.update_wrapper( | |
types.FunctionType( | |
_patch_code(func_or_code.__code__), | |
func_or_code.__globals__, | |
func_or_code.__name__, | |
func_or_code.__defaults__, | |
func_or_code.__closure__, | |
), | |
func_or_code | |
) | |
def seven_factory(): | |
return 7 | |
@with_list_concat | |
def foo(): | |
a = 1 | |
print(a) # 1 | |
b = [1, 2, 3] [4] | |
print(b) # [1, 2, 3, 4] | |
c = [1, 2, 3] [5, 6] | |
print(c) # [1, 2, 3, 5, 6] | |
d = [1, 2, 3] [(5, 6), 7] | |
print(d) # [1, 2, 3, (5, 6), 7] | |
e = [1, 2, 3] [(5, 6), seven_factory()] # actually, this one crashes | |
print(e) | |
foo() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment