Python不是強類型語言,開發人員沒有給數據定義類型的習慣。這樣雖然靈活,但處理複雜業務邏輯的時候卻不夠方便——缺少類型檢查可能致使很難發現錯誤,在IDE裏編碼時也沒有代碼提示。因此開發了這個小工具來解決它。python
首先定義業務類,並經過類變量定義每一個字段的類型。git
from typing import List class Person: name: str age: int class Company: name: str revenue: float employees: List[Person]
之因此選擇類變量來定義,是由於它最簡潔和直觀。相比之下,若是在__init__方法中初始化實例變量,是沒有辦法獲取類型定義(type_hint)的;若是用@property註解或者getter,setter方法的話,顯然就更復雜了。它們都不如直接定義類變量簡單優美。不過使用類變量也有缺點:就是它在這裏被當成元數據來使用了,若是真的須要定義類級別共享的變量,沒法區分。這個問題能夠在後面經過開發自定義註解來解決。github
下一步就能夠把符合這個類定義結構的dict-list嵌套數據,轉化爲該類實例對象了:json
from objtyping import objtyping company1 = 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嵌套的形式編碼
from objtyping import objtyping dict_list = objtyping.to_dict_list(company1)
此時的dict_list對象,就是一大堆dict和list層級嵌套的原始類型數據code
Python沒有js那麼方便的初始化對象方式,但有這個工具就能夠這樣寫(就是前面基礎使用的彙總):orm
from typing import List from objtyping import objtyping class Person: name: str age: int class Company: name: str revenue: float employees: List[Person] def __str__(self): # 其實通常可能都是這樣簡單用一下的 return "'{}' has {} employees: {}".format(self.name, len(self.employees), ' and '.join(map(lambda emp: 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)
輸出結果:對象
'Apple' has 2 employees: Tom and Jerry
Python的常見的序列化需求,包括json和yaml數據格式,它們都有相對完善的處理庫。但一樣是不強調類型的緣故,它們處理的對象都是原始的dict-list格式。正好能夠藉助這個工具實現進一步轉化。開發
示例
import json import sys from typing import List from objtyping import objtyping class X: x: int y: str class A: q: str a: str b: int c: List[X] if __name__ == '__main__': print("\r\n-----json-------") json_obj = json.loads('{"q":9, "a":"Mark", "b":3, "c":[{"x":15, "y":"male"},{"x":9, "y":"female", "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": "Mark", "b": 3, "c": [{"x": 15, "y": "male"}, {"x": 9, "y": "female", "z": 13}]}
這裏須要注意的是:原本屬性"q",在最初的json結構中,是個數字,但因爲類變量定義中是字符串,轉換成業務對象之後,它的類型就是字符串了——objtyping工具,會試圖按照類定義,在基礎類型之間強制轉換。
示例
import sys from ruamel.yaml import YAML from typing import List from objtyping import objtyping class X: x: int y: str class A: q: str a: str b: int c: List[X] if __name__ == '__main__': print("\r\n-----yaml-------") yaml = YAML() yaml_obj = yaml.load(''' q: 9 a: Mark b: 3 c: - x: 15 y: male - x: 9 y: female 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: Mark b: 3 c: - x: 15 y: male - x: 9 y: female z: 13
這裏的屬性"q"一樣被強轉了類型。