对于传入的参数做类型检测,(类型注解)
1 # 在init之前做判断,但是耦合度太高 2 class Person: 3 def __init__(self, name:str, age:int): 4 params = ((name, str), (age, int)) 5 if not self.typecheck(params): 6 raise TypeError 7 self.name = name 8 self.age = age 9 10 def typecheck(self, params): 11 for p, t in params: 12 if not isinstance(p, t): 13 return False 14 return True 15 16 使用装饰器,使用inspect模块完成 17 18 import inspect 19 20 def typecheck(fn): 21 def wrapper(*args, **kwargs): 22 sig = inspect.signature(fn) 23 params = sig.parameters # OrderedDict([('self', <Parameter "self">), ('name', <Parameter "name: str">), ('age', <Parameter "age: int">)]) 24 25 keys = list(params.keys()) 26 print(keys) 27 values = list(params.values()) 28 print(values) 29 # 位置参数 30 for i, v in enumerate(args[1:]): 31 if type(v) is not (values[1:])[i].annotation: 32 raise Exception('-------Different Tyeps') 33 # 关键字参数 34 for i, v in kwargs.items(): # i=age, v=12 35 for key in keys: 36 if key == i and params[key].annotation != inspect._empty and type(v) is not params[key].annotation: 37 raise Exception('+++++++Different Types') 38 return wrapper 39 40 class Person: 41 42 @typecheck # __init__ = typecheck(__init__) 43 def __init__(self, name:str, age:int=12): 44 self.name = name 45 self.age = age 46 47 p = Person('jack', age=12) # 没有键值对的方式 48 49 使用描述器 将属性放到自己的属性字典中 50 class TypeCheck: 51 def __init__(self, flag, type): 52 self.flag = flag 53 self.type = type 54 55 def __get__(self, instance, owner): 56 return instance.__dict__[self.flag] 57 58 def __set__(self, instance, value): 59 if isinstance(value, self.type): 60 instance.__dict__[self.flag] = value 61 else: 62 raise TypeError 63 64 65 class Person: 66 name = TypeCheck('name', str) 67 age = TypeCheck('age', int) 68 69 def __init__(self, name:str, age:int): 70 self.name = name 71 self.age = age 72 73 p = Person('tom', 18) 74 print(p.name) 75 print(p.age) 76 print(p.__dict__) 77 78 使用描述器 将属性放到描述器实例的属性字典中 79 class TypeCheck: 80 def __init__(self, flag, type): 81 self.flag = flag 82 self.type = type 83 self.data = {} 84 85 def __get__(self, instance, owner): 86 # return instance.__dict__[self.flag] 87 print(self.__dict__) 88 return self.data[self.flag] 89 90 def __set__(self, instance, value): 91 if isinstance(value, self.type): 92 # instance.__dict__[self.flag] = value 93 self.data[self.flag] = value 94 else: 95 raise TypeError 96 97 class Person: 98 name = TypeCheck('name', str) 99 age = TypeCheck('age', int) 100 101 def __init__(self, name:str, age:int): 102 self.name = name 103 self.age = age 104 105 p = Person('tom', 12) 106 print(p.name) 107 print(p.age) 108 print(p.__dict__) 109 110 上面属于硬编码,将描述器写到 逻辑代码中。 111 现在将其提取出来,作为装饰器 112 函数装饰器 113 class TypeCheck: 114 def __init__(self, flag, type): 115 self.flag = flag 116 self.type = type 117 118 def __get__(self, instance, owner): 119 return instance.__dict__[self.flag] 120 121 def __set__(self, instance, value): 122 if isinstance(value, self.type): 123 instance.__dict__[self.flag] = value 124 else: 125 raise TypeError 126 127 import inspect 128 def typeassert(cls): 129 sig = inspect.signature(cls) 130 params = sig.parameters 131 for flag, value in params.items(): 132 # cls.__dict__[flag] = TypeCheck(flag, value.annotation) # 只有实例能添加属性到字典中,通过操作字典 133 if value.annotation != inspect._empty: # 或者,value.empty 134 setattr(cls, flag, TypeCheck(flag, value.annotation)) 135 return cls 136 137 @typeassert # Person=typeassert(Person) 138 class Person: 139 # name = TypeCheck('name', str) 140 # age = TypeCheck('age', int) 141 def __init__(self, name:str, age:int): 142 self.name = name 143 self.age = age 144 145 p = Person('tom', 18) 146 print(p.name) 147 print(p.age) 148 print(p.__dict__) 149 150 上面属于硬编码,将描述器写到 逻辑代码中。 151 现在将其提取出来,作为装饰器 152 类装饰器 153 154 class TypeCheck: 155 def __init__(self, flag, type): 156 self.flag = flag 157 self.type = type 158 159 def __get__(self, instance, owner): 160 return instance.__dict__[self.flag] 161 162 def __set__(self, instance, value): 163 if isinstance(value, self.type): 164 instance.__dict__[self.flag] = value 165 else: 166 raise TypeError 167 168 import inspect 169 class TypeAssert: 170 def __init__(self, cls): 171 sig = inspect.signature(cls) 172 params = sig.parameters 173 for flag, value in params.items(): 174 if value.annotation != inspect._empty: # 或者,value.empty 175 setattr(cls, flag, TypeCheck(flag, value.annotation)) 176 self.cls = cls 177 178 def __call__(self, *args, **kwargs): 179 return self.cls(*args, **kwargs) 180 181 @TypeAssert # Person=TypeAssert(Person) 182 class Person: 183 def __init__(self, name:str, age:int): 184 self.name = name 185 self.age = age 186 187 p = Person('tom', 18) 188 print(p.__dict__) 189 print(p.name) 190 print(p.age) 191 print(p.__dict__)
为什么要坚持,想一想当初!