对于传入的参数做类型检测,(类型注解)

  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__)
为什么要坚持,想一想当初!
原文地址:https://www.cnblogs.com/JerryZao/p/9692972.html