
import gc
import sys
import struct
import opcode
import 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))

