<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 6404字,需瀏覽 13分鐘

           ·

          2020-12-08 22:12

          作者:萬(wàn)百入年許老

          來(lái)源:SegmentFault 社區(qū)




          場(chǎng)景


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




          環(huán)境


          • Python3.8
          • openpyxl==3.0.5




          前置知識(shí)


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


          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í)例化對(duì)象


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

          def test(clazz): """ 實(shí)例化對(duì)象 :param clazz: 要實(shí)例化的類型 """ x = clazz() setattr(x, "name", "老王") x.print_sth() # 打印:測(cè)試實(shí)例化方法 老王test(Person)





          Excel操作類庫(kù) - 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()
          # 讀取上一個(gè)代碼塊創(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ū)分大小寫(xiě))轉(zhuǎn)換為bool值 長(zhǎng)得像數(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對(duì)象 過(guò)濾掉為空行 :param file_path:Excel文件路徑 :param clazz:結(jié)果轉(zhuǎn)換為clazz對(duì)象 :return: 對(duì)象列表的列表,結(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í)例化對(duì)象 instance = clazz() for column_index in range(len(row)): setattr(instance, table_heads[column_index], _convert_value(row[column_index].value))
          # 過(guò)濾空行(所有屬性均為None的對(duì)象) 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__: # 過(guò)濾"_"開(kāi)頭的屬性 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
          # 示例對(duì)象class A: name=None age=None isManager=None
          # 讀取Excel文件,并轉(zhuǎn)換為指定類型對(duì)象列表tables = ExcelHelper.convert_2_class("123.xlsx", A)
          # 保存為Excela1=A()table=[a1]ExcelHelper.save("456.xls", [table])


          注意


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


          表1-1

          參考資料

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

          以上




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

          -?END -

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

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费看一级黄色录像 | 2017大香蕉 | 九一网站平台直接观看 | 人人插人人草 | 中文字幕日本第一页 |