Python应用反射实现Excel与对象之间的转换
代码在最下方,伸手党间接滚动到最初
场景
须要从Excel中加载到内存中,转换为class对象执行操作
环境
- Python3.8
- openpyxl==3.0.5
前置常识
反射(仅介绍这个帮忙类用到的几个反射办法)
setattr、getattr
class Person(): name = None def __init__(self, name): self.name = namep = Person("laowang")n = getattr(p, "name")print(n)# 打印后果: laowangsetattr(p, "name", "laoxu")n2 = getattr(p, "name")print(n2)# 打印后果: laoxu
反射实例化对象
class Person(): name = None def print_sth(self): print("测试实例化办法", self.name)def test(clazz): """ 实例化对象 :param clazz: 要实例化的类型 """ x = clazz() setattr(x, "name", "老王") x.print_sth() # 打印: 测试实例化办法 老王test(Person)
Excel操作类库 - openpyxl
创立Excel
from openpyxl import Workbookwb = Workbook()ws1 = wb.activews1.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 Workbookdef print_row(arr): """为了显示不便,打印行""" for item in arr: print(item,end="\t\t|") print()# 读取上一个代码块创立的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) # 获取表数据 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)# 打印后果如下:# ----------------- 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 isfilefrom openpyxl import load_workbook, Workbookdef _convert_value(value): """ 将单元格中数据,辨别根本类型 相似"true"/"false"(不辨别大小写)转换为bool值 长得像数字的转换为float类型 其余(空格、空行)转换为None :param value: 单元格的值 :return: 转换后的类型 """ 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 valueclass ExcelHelper: """ Excel帮忙类 """ @classmethod def convert_2_class(cls, file_path, clazz): """ 转换为class,可转换多张sheet表,转换为对立clazz对象 过滤掉为空行 :param file_path:Excel文件门路 :param clazz:后果转换为clazz对象 :return: 对象列表的列表,构造为[[clazz(),clazz()],[clazz()]] """ if not file_path.endswith(".xlsx"): raise ValueError("文件必须为.xlsx结尾的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) # 获取表数据 table = [] for row in ws.iter_rows(min_row=2): # 实例化对象 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结尾的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) # 增加数据 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("创立Excel失败")
应用办法
# 导入类from excel_helper import ExcelHelper# 示例对象class A: name=None age=None isManager=None# 读取Excel文件,并转换为指定类型对象列表tables = ExcelHelper.convert_2_class("123.xlsx", A)# 保留为Excela1=A()table=[a1]ExcelHelper.save("456.xls", [table])
留神
- 该帮忙类均为@classmethod
- 该帮忙类应用反射实现,所以表头名称须要与对象的字段名一一对应(如代码中的class A 与 下表"表1-1")
- Excel中能够有多张表(sheet tab),所以参数为对象列表的列表,请留神对应关系
- 以后读取Excel仅能转换为一个class类型,所以多种表构造请应用多张表
表1-1
name | age | isManager |
---|---|---|
老王 | 18 | True |
Tom | 28 | FALSE |
参考资料
PYTHON里的反射(自学习)
以上