見るも無惨なキモイコードシリーズ
というか引数を内部でポンポンいじられるのって単純な話分かりにくいよ。関数で加工した値を再度代入する、という形はやっぱり分かりやすい。
import sys from opcode import * def callee_names(frame_depth=1): result = [] frame = sys._getframe(frame_depth + 2) co = frame.f_code code = co.co_code i = 0; n = frame.f_lasti - 2 oparg = extended_arg = 0 while i < n: c = code[i] op = ord(c) i = i + 1 if op >= HAVE_ARGUMENT: oparg = ord(code[i]) + ord(code[i + 1]) * 256 + extended_arg extended_arg = 0 i = i + 2 if op == EXTENDED_ARG: extended_arg = oparg * 65536L if op in hasconst: result.append(co.co_consts[oparg]) elif op in hasname: result.append(co.co_names[oparg]) elif op in haslocal: result.append(co.co_varnames[oparg]) elif op in hasfree: result.append((co.co_cellvars + co.co_freevars)[oparg]) callee = sys._getframe(frame_depth + 1) argcount = callee.f_code.co_argcount index = argcount if callee.f_code.co_flags & 0x04: argcount += len(callee.f_locals[callee.f_code.co_varnames[index]]) index += 1 if callee.f_code.co_flags & 0x08: argcount += len(callee.f_locals[callee.f_code.co_varnames[index]]) * 2 result = result[-argcount:] return result class ByRef(object): def __init__(self): self.__dict__['locals'] = callee_names(1) def __setattr__(self, _name, _value): callee = sys._getframe(1) caller = sys._getframe(2) argindex = list(callee.f_code.co_varnames).index(_name) localname = self.__dict__['locals'][argindex] caller.f_locals[localname] = _value if __name__ == '__main__': def foo(v1, v2, *args, **kwargs): byref = ByRef() # first of all, create ByRef instance. byref.v2 = v1 * 2 a = 10 b = 0 c = -10 print b foo(a, b, c, foo=1) print b
例によって動かない可能性がある