1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Python 使用反射實(shí)現(xiàn) Excel 與對象之間的轉(zhuǎn)換

        共 6404字,需瀏覽 13分鐘

         ·

        2020-12-08 22:12

        作者:萬百入年許老

        來源:SegmentFault 社區(qū)




        場景


        需要從Excel中加載到內(nèi)存中,轉(zhuǎn)換為class對象執(zhí)行操作




        環(huán)境


        • Python3.8
        • openpyxl==3.0.5




        前置知識


        反射(僅介紹這個幫助類用到的幾個反射方法)


        setattr、getattr

        class Person():    name = None
        def __init__(self, name): self.name = name

        p = Person("laowang")n = getattr(p, "name")print(n)# 打印結(jié)果:laowang
        setattr(p, "name", "laoxu")n2 = getattr(p, "name")print(n2)# 打印結(jié)果:laoxu


        反射實(shí)例化對象


        class?Person():    name = None
        def print_sth(self): print("測試實(shí)例化方法", self.name)

        def test(clazz): """ 實(shí)例化對象 :param clazz: 要實(shí)例化的類型 """ x = clazz() setattr(x, "name", "老王") x.print_sth() # 打?。簻y試實(shí)例化方法 老王test(Person)





        Excel操作類庫 - openpyxl


        創(chuàng)建Excel


        from openpyxl import Workbook

        wb = Workbook()ws1 = wb.active
        ws1.append(['name', 'age', 'isManager', 'remark'])ws1.append(['', '', '', ' '])ws1.append(['老王', '18', 'false', ' '])ws1.append(['laoxu', '28.4', 'TRUE', 'zaoricaifuziyou'])ws1.append(['', '', '', ' '])
        ws2 = wb.create_sheet("ws2")
        ws2.append(['name', 'age', 'isManager', 'remark'])ws2.append(['小李', '50', 'TRuE', 'fly knife'])ws2.append(['', '', '', ' '])ws2.append(['aaa', '11', 'false', 'hehehe'])
        wb.save("test_convert_2_class.xlsx")


        讀取Excel


        from openpyxl import Workbook
        def print_row(arr): """為了顯示方便,打印行""" for item in arr: print(item,end="\t\t|") print()
        # 讀取上一個代碼塊創(chuàng)建的Excel代碼work_book = load_workbook("test_convert_2_class.xlsx")result = []for sheet_name in work_book.sheetnames: print("-----------------",sheet_name,"-----------------") ws = work_book[sheet_name]
        # 獲取表頭 table_heads = [] for title_row in ws.iter_rows(max_row=1): for cell in title_row: table_heads.append(cell.value) print_row(table_heads) # 獲取表數(shù)據(jù) table = [] for row in ws.iter_rows(min_row=2): row_data=[] for column_index in range(len(row)): row_data.append(row[column_index].value) print_row(row_data)# 打印結(jié)果如下:# ----------------- Sheet -----------------# name |age |isManager |remark |# None |None |None | |# 老王 |18 |false | |# laoxu |28.4 |TRUE |zaoricaifuziyou |# None |None |None | |# ----------------- ws2 -----------------# name |age |isManager |remark |# 小李 |50 |TRuE |fly knife |# None |None |None | |# aaa |11 |false |hehehe |




        伸手黨代碼


        excel_helper.py


        import osimport refrom os.path import isfile
        from openpyxl import load_workbook, Workbook

        def _convert_value(value): """ 將單元格中數(shù)據(jù),區(qū)分基本類型 類似"true"/"false"(不區(qū)分大小寫)轉(zhuǎn)換為bool值 長得像數(shù)字的轉(zhuǎn)換為float類型 其他(空格、空行)轉(zhuǎn)換為None :param value: 單元格的值 :return: 轉(zhuǎn)換后的類型 """ value_str = str(value).lower() if value_str == 'true': return True elif value_str == 'false': return False elif re.match(r"^[+|-]?\d+.?\d*$", value_str): return float(value_str) elif re.match(r"^\s*$", value_str): return None else: return value

        class ExcelHelper: """ Excel幫助類 """
        @classmethod def convert_2_class(cls, file_path, clazz): """ 轉(zhuǎn)換為class,可轉(zhuǎn)換多張sheet表,轉(zhuǎn)換為統(tǒng)一clazz對象 過濾掉為空行 :param file_path:Excel文件路徑 :param clazz:結(jié)果轉(zhuǎn)換為clazz對象 :return: 對象列表的列表,結(jié)構(gòu)為[[clazz(),clazz()],[clazz()]] """ if not file_path.endswith(".xlsx"): raise ValueError("文件必須為.xlsx結(jié)尾的Excel文件") if not isfile(file_path): raise FileNotFoundError("文件路徑 {0} 不存在".format(file_path)) work_book = load_workbook(file_path) result = [] for sheet_name in work_book.sheetnames: ws = work_book[sheet_name]
        # 獲取表頭 table_heads = [] for title_row in ws.iter_rows(max_row=1): for cell in title_row: table_heads.append(cell.value) # 獲取表數(shù)據(jù) table = [] for row in ws.iter_rows(min_row=2): # 實(shí)例化對象 instance = clazz() for column_index in range(len(row)): setattr(instance, table_heads[column_index], _convert_value(row[column_index].value))
        # 過濾空行(所有屬性均為None的對象) is_valid = False for attr in instance.__dict__: if not attr.startswith("_") and instance.__dict__[attr] is not None: is_valid = True break if is_valid: table.append(instance) result.append(table) return result
        @classmethod def save(cls, file_path, tables): if not file_path.endswith(".xlsx"): raise ValueError("文件必須為.xlsx結(jié)尾的Excel文件") work_book = Workbook() is_first = True for table in tables: if is_first: ws = work_book.active is_first = False else: ws = work_book.create_sheet() # 添加表頭 table_heads = [] for attr in table[0].__dict__: # 過濾"_"開頭的屬性 if not attr.startswith("_"): table_heads.append(attr) ws.append(table_heads)
        # 添加數(shù)據(jù) for row in table: data = [] for head in table_heads: data.append(getattr(row, head)) ws.append(data) try: # 生成保存文件夾路徑 folder_index = max(file_path.rfind("\\"), file_path.rfind("/")) if folder_index != -1: folder_path = file_path[0:folder_index] if not os.path.exists(folder_path): os.mkdir(folder_path) work_book.save(file_path) except Exception: raise OSError("創(chuàng)建Excel失敗")


        使用方法


        # 導(dǎo)入類from excel_helper import ExcelHelper
        # 示例對象class A: name=None age=None isManager=None
        # 讀取Excel文件,并轉(zhuǎn)換為指定類型對象列表tables = ExcelHelper.convert_2_class("123.xlsx", A)
        # 保存為Excela1=A()table=[a1]ExcelHelper.save("456.xls", [table])


        注意


        • 該幫助類均為@classmethod
        • 該幫助類使用反射實(shí)現(xiàn),所以表頭名稱需要與對象的字段名一一對應(yīng)(如代碼中的class A 與 下表"表1-1")
        • Excel中可以有多張表(sheet tab),所以參數(shù)為對象列表的列表,請注意對應(yīng)關(guān)系
        • 當(dāng)前讀取Excel僅能轉(zhuǎn)換為一個class類型,所以多種表結(jié)構(gòu)請使用多張表


        表1-1

        參考資料

        PYTHON里的反射(自學(xué)習(xí)):https://www.cnblogs.com/kongk/p/8645202.html

        以上




        點(diǎn)擊左下角閱讀原文,到?SegmentFault 思否社區(qū)?和文章作者展開更多互動和交流。

        -?END -

        瀏覽 39
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            欧美四五十路熟妇 | 欧美日韩亚洲色图 | 性农村人freesex | 嫩草午夜福利电影 | 中文字幕乱伦小说 | 操毛网站| 91日韩国产 | 黄色www在线观看 | 中国黄色大片 | 91无码粉嫩小泬无套在线哈尔滨 |