objtyping有类型定义的对象转换器是因为Python不是强类型语言,开发者没有为数据定义类型的习惯。这样虽然灵活,但在处理复杂的业务逻辑时并不方便——缺少类型检查可能导致错误难以发现,而且在IDE中编码时没有代码提示。于是开发了这个小工具来解决。基本用法首先定义业务类,通过类变量定义各个字段的类型。fromtypingimportListclassPerson:name:strage:intclassCompany:name:strrevenue:floatemployees:List[Person]类变量定义是因为它最简洁直观。相反,如果在__init__方法中初始化实例变量,就没有办法得到类型定义(type_hint);如果使用@property注解或者getter、setter方法,显然要复杂一些。它们都没有直接定义类变量那么简单和优雅。但是,使用类变量也有缺点:它在这里用作元数据。如果你真的需要定义在类级别共享的变量,你无法区分它们。稍后可以通过开发自定义注释来解决此问题。接下来就是将符合该类定义结构的dict-list嵌套数据转换为该类的实例对象:fromobjtypingimportobjtypingcompany1=objtyping.from_dict_list({'name':'Apple','revenue':18.5,'employees':[{'name':'Tom','age':20},{'name':'Jerry','age':31}]},Company)此时company1是完整的Company对象现在,可以直接使用company1.name、company1.employees[0].name等形式访问里面的属性。当然业务对象也可以转换回dict-list的嵌套形式fromobjtypingimportobjtypingdict_list=objtyping.to_dict_list(company1)此时的dict_list对象是大量原始类型数据嵌套在dict和list水平。使用场景初始化ObjectPython没有js这么方便的初始化对象的方法,但是有了这个工具,你可以这样写(之前基本使用的总结):fromtypingimportListfromobjtypingimportobjtypingclassPerson:name:strage:intclassCompany:name:strrevenue:floatemployees:List[Person]def__str__(self):#其实用return"'{}'has{}employees:{}".format(self.name,len(self.employees),'and'.join(map(lambdaemp:emp.name,self.employees)))if__name__=='__main__':company1=objtyping.from_dict_list({'name':'Apple','revenue':18.5,'employees':[{'name':'Tom','age':20},{'name':'Jerry','age':31}]},company)print(company1)outputresult:'Apple'has2employees:TomandJerry序列化/反序列化Python常见的序列化需求,包括json和yaml数据格式,有比较完善的处理库。但也是为了不强调类型,他们处理的对象都是原始的dict-list格式。正是这个工具可以用来实现进一步的改造。json示例importjsonimportsysfromtypingimportListfromobjtypingimportobjtypingclassX:x:inty:strclassA:q:stra:strb:intc:List[X]if__name__=='__main__':print("\r\n-----json--------")json_obj=json.loads('{"q":9,"a":"Mark","b":3,"c":[{"x":15,"y":"男"},{"x":9,"y":"女","z":13}]}')typed_obj=objtyping.from_dict_list(json_obj,A)d_l_obj=objtyping.to_dict_list(typed_obj)print(json.dumps(d_l_obj))sys.exit()输出-----json------{"q":"9","a":"标记","b":3,"c":[{"x":15,"y":"男"},{"x":9,"y":"女","z":13}]}这里需要注意的是,原来的属性“q”在原来的json结构中是一个数字,但是由于类变量定义是字符串,所以在转换成业务对象后,其类型是字符串———objtyping工具将尝试根据类定义在底层类型之间进行转换。yaml示例importsysfromruamel.yamlimportYAMLfromtypingimportListfromobjtypingimportobjtypingclassX:x:inty:strclassA:q:stra:strb:intc:List[X]if__name__=='__main__':print("\r\n-----yaml------")yaml=YAML()yaml_obj=yaml.load('''q:9a:Markb:3c:-x:15y:男性-x:9y:女性z:13''')typed_obj=objtyping.from_dict_list(yaml_obj,A)d_l_obj=objtyping.to_dict_list(typed_obj)yaml.dump(d_l_obj,sys.stdout)sys.exit()输出结果-----yaml--------q:'9'a:Markb:3c:-x:15y:male-x:9y:femalez:13这里的属性“q”是also类型是强制的。项目地址:github
