# Some type checking in Python

This topic is 4102 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I've been playing around with the idea of adding some run-time typechecking in Python, just for debugging purposes. That is, type-checking is only on during the development of the program, and probably disabled when it's about to be released for the users. I've come up with a simple module that handles most of this, so I thought I shared. First things first, this is the module: safe.py
import types

#just for some convenience...
number=(int,long,float)
iterable=(list,tuple)

def safe(*sig):
def _f(f):
func=partial(safecall,f,sig)
func.__doc__=f.__doc__
func.sig=sig
return func
return _f

#Uncomment the below if you want to disable type-checking entirely(even if the func is decorated as @safe)
"""
def safe(*sig):
def _f(f):
return f
return _f
"""

def partial(f,*bind_args):
def _f(*args):
return f(*(bind_args+args))
return _f

def safecall(f,sig,*args):
i=0
l=len(sig)
#check arguments
for (arg,typ) in zip(args,sig[0:l-1]):
if not isinstance(arg,typ):
raise TypeError,"Incorrect type of arg"+str(i)+":expected "+str(typ)+" got "+str(type(arg))+" instead"
i=i+1
result=f(*args)
#check result
if not isinstance(result,sig[l-1]):
raise TypeError,"Wrong result type: expected"+str(sig[l-1])+" got "+str(type(result))+" instead"
return result


The idea is that you use the decorator @safe to give a function a signature. So, if the function accepts two ints and returns a bool, the decorator will be: @safe(int,int,bool) Instead of one type, you can define a tuple of types the arguments will be checked against. To make the above function work for any kind of number(int,long,float), you just do: number=(int,long,float) @safe(number,number,bool) Of course, inheritence rules are applied during type checking.Also,if you don't want to type-check a specific argument, and want it to accept any type, you can use the generic object type. What's more, the function/method gets a "sig" member that contains the "signature" as defined in the decorator. So you can just do "print foo.sig" for a @safe "foo" function to inspect the types of arguments and result it expects. The below code demonstrates in more detail the use of the module(it supports methods too).
from safe import *
from types import *

@safe(number,number,number)
return x+y

@safe(str,str,str)
def concat(s1,s2):
return s1+s2

class Foo(object):
@safe(object,str,number,iterable,NoneType)
def __init__(self,name,x,lst):
self.x=x
self.name=name
self.lst=lst

#Print some signatures...
print "concat:",concat.sig
print "Foo.__init__:",Foo.__init__.sig

#All these are legal:
foo=Foo("Foo",42,[1,2,3])
print concat("Hello ","world")

#All these produce exceptions:
#print concat(1,2)
#foo=Foo("Foo","42",1)


I hope some at least Pythonistas will find it useful to make the debugging sessions somewhat easier. Also, don't be afraid to leave the comment if you think this idea and module are just awful ;)

##### Share on other sites
kind of reminds me of this ;)

##### Share on other sites
Ah... I tried to link to this:

##### Share on other sites
Hm yeah, those do look similar :) Haven't seen this before, thanks for the link.

• 10
• 17
• 9
• 14
• 41