‘strict’ typing of function arguments in python
Sometimes you just need strict variable typing in python. For example if you provide an XML-RPC function, where you have to ensure that the incoming data has the correct type. One solution for this is to write type-checking and converting manually within every function. Since that idea is not very nice and clean, i wrote a function and function decorator that can ensure that the function is always called with the desired types as arguments. To achieve that you need to use a certain naming scheme for the functions arguments: variableType_variableName. So int_a, str_s, list_myList, etc. (see example in code)
code (working example, just run):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | # strictly typed python function arguments example # Thomas Fischer <thomas{AT}thomasfischer{DOT}biz> # function that checks the variable name and its type # to use a certain type for a variable, just write variabletype_variablename # for example: int_number, str_s, list_l def checkFunctionArgumentTypes(function_pointer, args): args = list(args) # we want to assign stuff to it later on # now list some built-in types we check for arg_types = {'int':int, 'str':str, 'list':list, 'dict':dict, 'bool':bool, 'unicode':unicode, 'tuple':tuple, 'buffer':buffer, 'xrange':xrange, 'float':float, 'long':long, 'complex':complex, 'set':set, 'frozenset':frozenset} # care about default arguments (means args <= len of function arguments) arg_num = len(args) self_exist = False if function_pointer.func_code.co_argcount > 0 and function_pointer.func_code.co_varnames[0] == 'self': self_exist = True for argnum in range(0, arg_num): arg_def = None if self_exist: arg_def = function_pointer.func_code.co_varnames[argnum+1] else: arg_def = function_pointer.func_code.co_varnames[argnum] arg_ext = args[argnum] atype = None for arg_type in arg_types.keys(): if arg_def.startswith(arg_type): atype = arg_types[arg_type] break if atype is None: # we cannot check the type, since no keyword was found :-/ # maybe this is fatal for you and you want to return False as well continue # try to convert the type try: args[argnum] = atype.__call__(arg_ext) except Exception, e: res_str = "wrong type for function %s, argument %s (%d.) has to be type '%s' and not '%s'" % (function_pointer.__name__, arg_def, argnum, atype, type(arg_ext)) return False, res_str return True, args # some fancy function decorator that acts as a type checking wrapper around the function def checkArgumentTypes(f): def wrapper(*args, **kwargs): ok, args = checkFunctionArgumentTypes(f, args) if not ok: return ok, args f(*args, **kwargs) return wrapper # magic with python decorators :) @checkArgumentTypes def func1(str_s, int_number): print "func1 called with:", str_s, type(str_s), int_number, type(int_number) # ok, fits: print func1('test', 123) # ok, will be converted: print func1('test', '123') # fails, cannot convert ABC to int: print func1('test', 'ABC') |
the result upon run:
func1 called with: test <type 'str'> 123 <type 'int'> None func1 called with: test <type 'str'> 123 <type 'int'> None (False, "wrong type for function func1, argument int_number (1.) has to be type '<type 'int'>' and not '<type 'str'>'")
this thing makes using XML-RPC much easier