标签:
1 def fun(a:int, b=1, *c, d, e=2, **f) -> str: 2 pass
1 # _*_ coding: utf-8 2 import functools 3 import inspect 4 from itertools import chain 5 6 def typesafe(func): 7 """ 8 Verify that the function is called with the right arguments types and that 9 it returns a value of the right type, accordings to its annotations. 10 """ 11 spec = inspect.getfullargspec(func) 12 annotations = spec.annotations 13 14 for name, annotation in annotations.items(): 15 if not isinstance(annotation, type): 16 raise TypeError("The annotation for ‘%s‘ is not a type." % name) 17 18 error = "Wrong type for %s: expected %s, got %s." 19 # Deal with default parameters 20 defaults = spec.defaults or () 21 defaults_zip = zip(spec.args[-len(defaults):], defaults) 22 kwonlydefaults = spec.kwonlydefaults or {} 23 for name, value in chain(defaults_zip, kwonlydefaults.items()): 24 if name in annotations and not isinstance(value, annotations[name]): 25 raise TypeError(error % (‘default value of %s‘ % name, 26 annotations[name].__name__, 27 type(value).__name__)) 28 29 @functools.wraps(func) 30 def wrapper(*args, **kwargs): 31 # Populate a dictionary of explicit arguments passed positionally 32 explicit_args = dict(zip(spec.args, args)) 33 keyword_args = kwargs.copy() 34 # Add all explicit arguments passed by keyword 35 for name in chain(spec.args, spec.kwonlyargs): 36 if name in kwargs: 37 explicit_args[name] = keyword_args.pop(name) 38 39 # Deal with explict arguments 40 for name, arg in explicit_args.items(): 41 if name in annotations and not isinstance(arg, annotations[name]): 42 raise TypeError(error % (name, 43 annotations[name].__name__, 44 type(arg).__name__)) 45 46 # Deal with variable positional arguments 47 if spec.varargs and spec.varargs in annotations: 48 annotation = annotations[spec.varargs] 49 for i, arg in enumerate(args[len(spec.args):]): 50 if not isinstance(arg, annotation): 51 raise TypeError(error % (‘variable argument %s‘ % (i+1), 52 annotation.__name__, 53 type(arg).__name__)) 54 55 # Deal with variable keyword argument 56 if spec.varkw and spec.varkw in annotations: 57 annotation = annotations[spec.varkw] 58 for name, arg in keyword_args.items(): 59 if not isinstance(arg, annotation): 60 raise TypeError(error % (name, 61 annotation.__name__, 62 type(arg).__name__)) 63 64 # Deal with return value 65 r = func(*args, **kwargs) 66 if ‘return‘ in annotations and not isinstance(r, annotations[‘return‘]): 67 raise TypeError(error % (‘the return value‘, 68 annotations[‘return‘].__name__, 69 type(r).__name__)) 70 return r 71 72 return wrapper
对于上面的代码:
1 # _*_ coding: utf-8 2 import functools 3 import inspect 4 from itertools import chain 5 6 def precessArg(value, annotation): 7 try: 8 return annotation(value) 9 except ValueError as e: 10 print(‘value:‘, value) 11 raise TypeError(‘Expected: %s, got: %s‘ % (annotation.__name__, 12 type(value).__name__)) 13 14 def typesafe(func): 15 """ 16 Verify that the function is called with the right arguments types and that 17 it returns a value of the right type, accordings to its annotations. 18 """ 19 spec = inspect.getfullargspec(func) 20 annotations = spec.annotations 21 22 for name, annotation in annotations.items(): 23 if not isinstance(annotation, type): 24 raise TypeError("The annotation for ‘%s‘ is not a type." % name) 25 26 error = "Wrong type for %s: expected %s, got %s." 27 # Deal with default parameters 28 defaults = spec.defaults and list(spec.defaults) or [] 29 defaults_zip = zip(spec.args[-len(defaults):], defaults) 30 i = 0 31 for name, value in defaults_zip: 32 if name in annotations: 33 defaults[i] = precessArg(value, annotations[name]) 34 i += 1 35 func.__defaults__ = tuple(defaults) 36 37 kwonlydefaults = spec.kwonlydefaults or {} 38 for name, value in kwonlydefaults.items(): 39 if name in annotations: 40 kwonlydefaults[name] = precessArg(value, annotations[name]) 41 func.__kwdefaults__ = kwonlydefaults 42 43 @functools.wraps(func) 44 def wrapper(*args, **kwargs): 45 keyword_args = kwargs.copy() 46 new_args = args and list(args) or [] 47 new_kwargs = kwargs.copy() 48 # Deal with explicit argument passed positionally 49 i = 0 50 for name, arg in zip(spec.args, args): 51 if name in annotations: 52 new_args[i] = precessArg(arg, annotations[name]) 53 i += 1 54 55 # Add all explicit arguments passed by keyword 56 for name in chain(spec.args, spec.kwonlyargs): 57 poped_name = None 58 if name in kwargs: 59 poped_name = keyword_args.pop(name) 60 if poped_name is not None and name in annotations: 61 new_kwargs[name] = precessArg(poped_name, annotations[name]) 62 63 # Deal with variable positional arguments 64 if spec.varargs and spec.varargs in annotations: 65 annotation = annotations[spec.varargs] 66 for i, arg in enumerate(args[len(spec.args):]): 67 new_args[i] = precessArg(arg, annotation) 68 69 # Deal with variable keyword argument 70 if spec.varkw and spec.varkw in annotations: 71 annotation = annotations[spec.varkw] 72 for name, arg in keyword_args.items(): 73 new_kwargs[name] = precessArg(arg, annotation) 74 75 # Deal with return value 76 r = func(*new_args, **new_kwargs) 77 if ‘return‘ in annotations: 78 r = precessArg(r, annotations[‘return‘]) 79 return r 80 81 return wrapper 82 83 84 if __name__ == ‘__main__‘: 85 print("Begin test.") 86 print("Test case 1:") 87 try: 88 @typesafe 89 def testfun1(a:‘This is a para.‘): 90 print(‘called OK!‘) 91 except TypeError as e: 92 print("TypeError: %s" % e) 93 94 print("Test case 2:") 95 try: 96 @typesafe 97 def testfun2(a:int,b:str = ‘defaule‘): 98 print(‘called OK!‘) 99 testfun2(‘str‘,1) 100 except TypeError as e: 101 print("TypeError: %s" % e) 102 103 print("test case 3:") 104 try: 105 @typesafe 106 def testfun3(a:int, b:int = ‘str‘): 107 print(‘called OK‘) 108 except TypeError as e: 109 print(‘TypeError: %s‘ % e) 110 111 print("Test case 4:") 112 try: 113 @typesafe 114 def testfun4(a:int = ‘123‘, b:int = 1.2): 115 print(‘called OK.‘) 116 print(a, b) 117 testfun4() 118 except TypeError as e: 119 print(‘TypeError: %s‘ % e) 120 121 @typesafe 122 def testfun5(a:int, b, c:int = 1, d = 2, *e:int, f:int, g, h:int = 3, i = 4, **j:int) -> str : 123 print(‘called OK.‘) 124 print(a, b, c, d, e, f, g, h, i, j) 125 return ‘OK‘ 126 127 print("Test case 5:") 128 try: 129 testfun5(1.2, ‘whatever‘, f = 2.3, g = ‘whatever‘) 130 except TypeError as e: 131 print(‘TypeError: %s‘ % e) 132 133 print("Test case 6:") 134 try: 135 testfun5(1.2, ‘whatever‘, 2.2, 3.2, ‘e1‘, f = ‘123‘, g = ‘whatever‘) 136 except TypeError as e: 137 print(‘TypeError: %s‘ % e) 138 139 print("Test case 7:") 140 try: 141 testfun5(1.2, ‘whatever‘, 2.2, 3.2, 12, f = ‘123‘, g = ‘whatever‘) 142 except TypeError as e: 143 print(‘TypeError: %s‘ % e) 144 145 print("Test case 8:") 146 try: 147 testfun5(1.2, ‘whatever‘, 2.2, 3.2, 12, f = ‘123‘, g = ‘whatever‘, key1 = ‘key1‘) 148 except TypeError as e: 149 print(‘TypeError: %s‘ % e) 150 151 print("Test case 9:") 152 try: 153 testfun5(1.2, ‘whatever‘, 2.2, 3.2, 12, f = ‘123‘, g = ‘whatever‘, key1 = ‘111‘) 154 except TypeError as e: 155 print(‘TypeError: %s‘ % e) 156 157 print(‘Test case 10:‘) 158 @typesafe 159 def testfun10(a) -> int: 160 print(‘called OK.‘) 161 return ‘OK‘ 162 try: 163 testfun10(1) 164 except TypeError as e: 165 print(‘TypeError: %s‘ % e) 166 167 168 169 170
标签:
原文地址:http://www.cnblogs.com/boostable/p/python_annotations.html