Skip to content

Instantly share code, notes, and snippets.

@progval
Last active April 30, 2021 19:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save progval/ee62e41157d8e906d3ae46a3bf2577ba to your computer and use it in GitHub Desktop.
Save progval/ee62e41157d8e906d3ae46a3bf2577ba to your computer and use it in GitHub Desktop.
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