Python Evil

May 16, 2008 10:37

I was arguing with some Python code that used closures, and found it is very hard to manipulate them in inappropriate ways. Not being one to let both good programming practices and simple logic to get in my way, I hacked this together. Using this in production code may incur the wrath of all programmers within a 500 mile radius.



def top(x):
blarg = [2]
def mid(q):
data = {1:x}
asd = -1
return lambda n: data[n+asd+q[0]]
return mid(blarg)
f = top(2)

# ------

def get_closed_ns(f):
import itertools

def get_val(n):
try:
return f.func_closure[n].cell_contents
except AttributeError:
import types
import dis
old_code = f.func_code
code_string = (dis.opmap['LOAD_DEREF'], n%256, n//256, dis.opmap['RETURN_VALUE'])
new_code = types.CodeType(
0, #old_code.co_argcount,
old_code.co_nlocals,
old_code.co_stacksize,
old_code.co_flags,
''.join([chr(n) for n in code_string]), #old_code.co_code,
old_code.co_consts,
old_code.co_names,
old_code.co_varnames,
old_code.co_filename,
old_code.co_name,
old_code.co_firstlineno,
old_code.co_lnotab,
old_code.co_freevars,
old_code.co_cellvars,
)

new_f = types.FunctionType(
new_code,
f.func_globals,
f.func_name,
f.func_defaults,
f.func_closure,
)

return new_f()
names = {}
for i, name in enumerate(itertools.chain(f.func_code.co_cellvars, f.func_code.co_freevars)):
names[name] = get_val(i)
return names

print f(0)
ns = get_closed_ns(f)
ns['data'][1] = 'BOOM'
ns['q'][0] = 0

The function returns the entire closed namespace, though the usual reference mutation semantics apply (i.e. the closed value "asd" is not mutable). Enjoy!
Previous post Next post
Up