Skip to content

Instantly share code, notes, and snippets.

@Aragroth
Created August 22, 2021 09:39
Show Gist options
  • Select an option

  • Save Aragroth/0b4d1a6b97a633643b7b83e89a5da64f to your computer and use it in GitHub Desktop.

Select an option

Save Aragroth/0b4d1a6b97a633643b7b83e89a5da64f to your computer and use it in GitHub Desktop.
Change local variables of function
import gc
import ctypes
import sys
import dis
def change_locals(**new_locals):
def modify_function(func):
consts_arr = func.__code__.co_consts # all local-const values in funciton body
# sample idea of getting names, that correspond to local-const values
bytecode = dis.Bytecode(func)
position, params_order = 1, {}
last_operation_const_loading = False
for instr in bytecode:
if instr.opname == 'LOAD_CONST':
last_operation_const_loading = True
elif instr.opname == 'STORE_FAST':
if last_operation_const_loading:
params_order.update({instr.argval: position})
position += 1
else:
last_operation_const_loading = False
# maybe it is not needed?
gc.disable()
# PyTuple_SetItem works only on tuples with RefCount = 1 (newly created tuples), but
# only works when decreasing to 2 links. (May be sys.getrefcount creates additional link?)
modifying = ctypes.py_object(consts_arr)
decreased_count = 0
while sys.getrefcount(consts_arr) > 2:
ctypes.pythonapi.Py_DecRef(modifying)
decreased_count += 1
for var_name in new_locals:
if var_name not in func.__code__.co_varnames:
continue
replacing = new_locals[var_name]
repl = ctypes.py_object(replacing)
ctypes.pythonapi.Py_IncRef(repl) # not increasing link will cause to future Segfault, when program finished
ctypes.pythonapi.PyTuple_SetItem(modifying, ctypes.c_ssize_t(params_order[var_name]), repl)
# reincreasing links count to object
for _ in range(decreased_count):
ctypes.pythonapi.Py_IncRef(modifying)
gc.enable()
def execute_func(*args, **kwargs):
return func(*args, **kwargs)
return execute_func
return modify_function
@change_locals(x=150, c='Has changed')
def function():
c = 'Value'
x = 2
f = x
print(x + f, c)
function() # Output: 300 Has changed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment