Reputation: 5941
Is there a "standard" way to add simple dynamic type checking in Python, doing something like:
def add(a, b):
# Argument type check
check(a, int)
check(b, int)
# Calculate
res = a + b
# Result type check and return
check(res, int)
return res
An exception could then be raised by check
in case of a type mismatch.
I could of course cook something myself, doing isinstance(..., ...)
or type(...) == ...
, but I wonder if there is some "standard" module for this kind of type checking.
It would be nice if more complex type checking could also be done, like checking if an argument is either str
or int
, or for example a list
of str
.
I am aware that it somehow defies Pythons principle of duck typing, but I just spent several hours debugging due to an argument with wrong type, and it was a large program, so the cause shown up many nested calls from the reason.
Upvotes: 2
Views: 1270
Reputation: 82949
You could use a decorator function. Something like this:
def typecheck(*types):
def __f(f):
def _f(*args):
for a, t in zip(args, types):
if not isinstance(a, t):
print "WARNING: Expected", t, "got", a
return f(*args)
return _f
return __f
@typecheck(int, str, int)
def foo(a, b, c):
pass
foo(1, "bar", 5)
foo(4, None, "string")
Output (for the second call) is
WARNING: Expected <type 'str'>, got None
WARNING: Expected <type 'int'>, got 'string'
As it stands, this does not work for keyword parameters, though.
Edit: After some googling, I found some much more complex type checking decorators (1) (2) also supporting keyword parameters and return types.
Upvotes: 4
Reputation: 72855
There is mypy which is being considered for entry into Python proper but in general, there isn't any way to do what you want.
Your code should not depend on concrete types but on general interfaces (e.g. not whether two things are integers but whether they are "addable"). This allows you to take advantage of dynamic typing and write generic functions. If a type does not handle the interface you want, it will throw an exception which you can catch. So, your add would be better done like so.
def add(a, b):
try:
return a + b
except TypeError as t:
# some logging code here for your debugging ease
raise t
If you are on Python 3, there is optional type annotation for functions. This means that the following code is valid Python 3.
def add(a:int, b:int):
return a + b
I don't know if there any tools that take advantage of the hints to give you actual compile time checking though.
Upvotes: 2