Skip to content

Instantly share code, notes, and snippets.

@reacocard
Created July 4, 2011 08:17
Show Gist options
  • Save reacocard/1063050 to your computer and use it in GitHub Desktop.
Save reacocard/1063050 to your computer and use it in GitHub Desktop.
python decorator to make functions act statically typed
function = type(lambda x: x)
def __listcheck(typ, arg):
for i,x in enumerate(arg):
if not any((_typecheck(t, x) for t in typ)):
raise TypeError, "List member %s, \"%s\" is not of type %s!"%(i,x,typ)
return True
def __tuplecheck(typ, arg):
if len(typ) != len(arg):
raise TypeError, "Tuple length did not match."
for t,a,i in zip(typ, arg, range(len(typ))):
if not _typecheck(t, a):
raise TypeError, "Tuple member %s, \"%s\" is not of type %s!"%(i,a,t)
return True
def __setcheck(typ, arg):
for x in arg:
if not any((_typecheck(t, x) for t in typ)):
raise TypeError, "Set member \"%s\" is not of type %s!"%(x, typ)
return True
def __frozensetcheck(typ, arg):
for x in arg:
if not any((_typecheck(t, x) for t in typ)):
raise TypeError, "Frozenset member \"%s\" is not of type %s!"%(x, typ)
return True
def __dictcheck(typ, arg):
for k,v in arg.iteritems():
for ktyp, vtyp in typ.iteritems():
if _typecheck(ktyp, k) and _typecheck(vtyp, v):
break
else:
raise TypeError, "Dictionary member \"%s:%s\" is not of type %s!" % (k,v,typ)
return True
_deepchecks = {
list: __listcheck,
tuple: __tuplecheck,
set: __setcheck,
frozenset: __frozensetcheck,
dict: __dictcheck,
}
def _typecheck(typ, arg):
if isinstance(typ, type):
if not isinstance(arg, typ):
return False
elif isinstance(typ, function) and not typ(arg):
return False
elif not isinstance(arg, type(typ)):
return False
if type(arg) in _deepchecks:
if not _deepchecks[type(arg)](typ, arg):
return False
return True
def typed(*types, **kwtypes):
def outerwrapper(func):
def wrapper(*args, **kwargs):
if len(args) != len(types):
raise TypeError, "Incorrect argument count."
for typ, arg in zip(types, args):
if not _typecheck(typ, arg):
raise TypeError, "Argument %s failed typecheck." % (arg)
for kw, arg in kwargs.iteritems():
vtype = kwtypes.get(kw, None)
if vtype is None:
raise TypeError, "Encountered unexpected keyword argumement %s."%kw
_typecheck(vtype, arg)
return func(*args, **kwargs)
return wrapper
return outerwrapper
@typed(lambda x: x)
def identity(x):
print x
@typed([int])
def test(x):
print x
@typed((int, str))
def tupletest(tup):
print tup
@typed({int: int})
def intmap(d):
print d
@typed(int, a=str, b=int)
def opt(i, a=None, b=None):
print i, a, b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment