Friday, February 20, 2004

Evil returns

After months of having no good ideas for bad things to write, PEAK's NOT_GIVEN inspired me to write this little tidbit:


import gc, sys, struct, opcode, inspect

class NotGiven:
pass

def notGiven(param):
caller = sys._getframe(1)
for potentialFunction in gc.get_referrers(caller.f_code):
if getattr(potentialFunction, 'func_code', None) == caller.f_code:
break
elif getattr(getattr(potentialFunction, 'im_func', None), 'func_code', None) == caller.f_code:
potentialFunction = caller.im_func
break
else:
raise Exception("You're insane.")

argspec = inspect.getargspec(potentialFunction)
bytes = caller.f_code.co_code
lasti = caller.f_lasti
varStart = bytes.rindex(chr(opcode.opmap['LOAD_FAST']), 0, lasti)
(varIndex,) = struct.unpack('H', bytes[varStart+1:lasti])

value = argspec[3][varIndex]
return value is param

def foo(x = NotGiven(), y = NotGiven(), z = NotGiven()):
print 'x given?', not notGiven(x)
print 'y given?', not notGiven(y)
print 'z given?', not notGiven(z)

if __name__ == '__main__':
for args in ('', 'x', 'y', 'z', 'xy', 'xz', 'yz', 'xyz'):
print 'Passing', ' '.join(args) or 'nothing'
foo(**dict.fromkeys(args))


Thanks to teratorn for bringing NOT_GIVEN to my attention. :)

No comments:

Post a Comment