When Dynamic Type comes to Trouble
As a dynamic programming languages , Python don't have a type on variables , as well as a arguments . This feature save us a lot workload and it enable us to focus on logical of program .
def add(x, y):
return x+y
print add(5,6)
>> 11
print add("D","E")
>> "DE"
print add(5.0, 6)
>> 11.0
Above function is straightforward and works fine if x and y are passed with int/ float/ string .
But things may not expect as we thought, what if we pass a list parameter into this function ?
print add([5],6) Traceback (most recent call last): File "C:\Users\IBM_ADMIN\workspace\euler\test_blog.py", line 4, in <module> print add([5],6) File "C:\Users\IBM_ADMIN\workspace\euler\test_blog.py", line 2, in add return x+y TypeError: can only concatenate list (not "int") to list
When Decorator comes to Help
I won't take too much time explain on how decorator works . Pls refer to Bruce Eckel's post and Brian Holdefehr's post . Basically , we need a decorator to constrain the arguments passed into function, if the arguments are not consist with predefined value , we raise an exception and tell the user that parameters that won't match .
class ArgumentsCheck(object):
def __init__(self, *argstype):
self.argstype = argstype # store all parameters of decorater
def __call__(self, f):
def wrapped_f(*args):
# test if all type of params of decoratoer equals to those of functions
if not all([ type(a) == type(b) for a,b in zip(args, self.argstype) ]) :
# Not all equals, then print all type of decoratoer and those of functions
raise Exception("Invalid Params Type for Function %s,Argument Type required (%s) but a Type Supplied (%s) " % (f.__name__,','.join([ type(_).__name__ for _ in self.argstype]),','.join([ type(_).__name__ for _ in args])) )
else:
# if all params type matches ,then call the funtion with params
f(*args)
return wrapped_f
Define Parameter types of Function by Decoration
@ArgumentsCheck(0,0)
def func1(num1, num2): #the two params must be integers
print num1,num2
func1(1, 2) # this will be good
print "==================\n"
func1(1, 2.0) # this will fail
Output:
1 2
==================
Traceback (most recent call last):
File "C:\Users\IBM_ADMIN\workspace\euler\test_blog.py", line 27, in <module>
func1(1, 2.0) # this will fail
File "C:\Users\IBM_ADMIN\workspace\euler\test_blog.py", line 11, in wrapped_f
raise Exception("Invalid Params Type for Function %s,Argument Type required (%s) but a Type Supplied (%s) " % (f.__name__,','.join([ type(_).__name__ for _ in self.argstype]),','.join([ type(_).__name__ for _ in args])) )
Exception: Invalid Params Type for Function func1,Argument Type required (int,int) but a Type Supplied (int,float)
Conclusion:
By this decoration, we make Strong Typed arguments call in Python, even 0 and 0.0 behaves differently in this case .
You can get that workload savings you talk about in languages with statically typed variables - *if* the language has a good type inferencing engine. For instance, you can write:
add x y = x + 1
to define your add function, and just like python, it'll work for any type for which the + operator is defined. However, because the variables have types, the compiler (not the run-time system) will catch the error if you try and pass in a pair of variables which can't be added, saving even *more* time.
Given that the compiler already has a notion of types, then all you need is a notation to tell it which types you want to allow, and it can provide the same kind of restrictions that your decorator does. Again, caught at compile time instead of run time.
Now all I need is a language for general-purpose programming that I as much as I like Python that has a type system of that quality.
Hi,Mike
Thanks for your comment , that's a thoughtful thinking and I recently having a look at Ocaml(which is a strongly type language), and I can't agree more with you. That's a lot cooler if using a strongly typed language , not only saving developing workload but also enjoy a far more executing speed than Python.
I've been told that Ocaml is 70% elegance as Python and 70% speed performance of C. that's why I'm learning this language, it can served as a general-purpose language and strongly typed(with great type inference system)
Not as pretty as the decorator, but you can use isinstance() for example:-
def addsomething(x,y):
....if not isinstance(x, int):
........raise
I have used this on the odd occasion to implement overloaded function calls when other people are calling my code and I'm not sure what they are sending me
Cheers
Trevor
Hi, Trevor
I think the decorator will be good solution if the programming contains 100 functions which need constraints on their arguments. if the number of functions remains a small amount , your suggestion is more simple and elegant .