源代码
最近帮同事做一个历史数据的转换合并软件,使用python3从数据库读出数据,然后根据其中的几个字段相同的归类合并一行,然后输出到EXCEL中,数据大概是5W行,考虑到归类合并逻辑比较复杂,用python效率比较低,这部分用c/c++完成,python3调用生成的dll.
运行截图
代码如下:
python3代码如下:
# -*- coding: utf-8 -*- ''' Created on 2015年8月25日 @author: mikewolfli ''' from tkinter import * from tkinter import filedialog from tkinter import messagebox import psycopg2 import ctypes from ctypes import py_object from openpyxl import Workbook import openpyxl.writer.excel as excel_xlsx lib=ctypes.cdll.LoadLibrary("./libdeal_res") lib.combine_list.restype=py_object #combine_list参数是数据库读取的嵌套list[list,list,list...],
#返回list[list,list....]. 一定要有此行返回参数定义,否则print后显示的结果是整数
xls_header=["梯型","计划设计交单期","四位合同号","WBS项目号","合同名称","梯号","配置工程师","交付项目文档\n项目开始","项目分配","备注","BOM ransfer和项目release","配置完成刷新ID","梯数"] class Application(Frame): def __init__(self, master=None): Frame.__init__(self, master) self.pack() self.createWidgets() try: self.conn=psycopg2.connect(database="pgworkflow", user="postgres", password="1q2w3e4r", host="10.127.144.62", port="5432") except : messagebox.showerror(title="连接错误", message="无法连接") sys.exit() #self.cur = self.conn.cursor() def quit_func(self): if self.conn is not None: self.conn.close() self.quit() def save_file(self): file_str=filedialog.asksaveasfilename(title="导出文件", initialfile="d:/temp.xlsx",filetypes=[('excel file','.xlsx')]) if not file_str.endswith(".xlsx"): file_str+=".xlsx" self.file_string.set(file_str) def get_old_data(self): #cur_his=self.conn.cursor(cursor_factory=extras.DictCursor) cur_his=self.conn.cursor() cur_his.execute("select * from v_history_units_data order by wbs_no asc;") #cur_his.execute("select * from client_version") #col_names = [cn[0] for cn in cur_his.description] rows_his = cur_his.fetchall() #print(len(rows_his)) self.rows_lib= lib.combine_list(ctypes.py_object(rows_his))#通过ctypes.py_object转换list为
#c类型的PyObject* def export_file(self): if self.file_string.get()=="": messagebox.showerror("错误","未指定输出文件") return self.get_old_data() wb=Workbook() ws=wb.worksheets[0] for i in range(0,13): ws.cell(row=1,column=i+1).value=xls_header[i] i_row=2 for row in self.rows_lib: for j in range(0,13): ws.cell(row=i_row, column=j+1).value=row[j] i_row=i_row+1 if excel_xlsx.save_workbook(workbook=wb, filename=self.file_string.get()): messagebox.showinfo("输出","成功输出!") def createWidgets(self): self.path_label=Label(self) self.path_label["text"]="文件" self.path_label.grid(row=0, column=0) self.file_string=StringVar() self.path_entry=Entry(self, textvariable=self.file_string) self.path_entry["width"]=50 self.path_entry.grid(row=0, column=1, columnspan=2) self.path_entry["state"]="readonly" self.path_button=Button(self) self.path_button["text"]="变更文件" self.path_button.grid(row=0, column=3) self.path_button["command"]=self.save_file self.export_button=Button(self) self.export_button["text"]="导出数据" self.export_button.grid(row=1, column=0) self.export_button["command"]=self.export_file self.quit_button=Button(self) self.quit_button["text"]="退出" self.quit_button.grid(row=1, column=3) self.quit_button["command"]=self.quit_func if __name__ == '__main__': root=Tk() Application(root) root.title("历史数据导出程序") #root.geometry('640x360') #设置了主窗口的初始大小640x360 root.mainloop() root.destroy()
c/c++代码如下:
main.cpp
// The functions contained in this file are pretty dummy // and are included only as a placeholder. Nevertheless, // they *will* get included in the shared library if you // don't remove them :) // // Obviously, you 'll have to write yourself the super-duper // functions to include in the resulting library... // Also, it's not necessary to write every function in this file. // Feel free to add more files in this project. They will be // included in the resulting library. #include #include #include #include #include #include #include "py2cpp.hpp" using namespace std; using namespace dubzzz::Py2Cpp; struct data_row{ string lift_type; string plan_design_finish; string contract_id; string project_id; string project_name; string lift_id; string res_engineer; string act_design_finish; string prj_distribution; string remarks; string bom_trans_rel; string refresh_id; int lift_num; data_row & operator=(const data_row &other); };
data_row & data_row::operator=(const data_row &other) { if(&other!=this) { lift_type = other.lift_type; plan_design_finish = other.plan_design_finish; contract_id=other.contract_id; project_id = other.project_id; project_name = other.project_name; lift_id = other.lift_id; res_engineer=other.res_engineer; act_design_finish = other.act_design_finish; prj_distribution = other.prj_distribution; remarks = other.remarks; bom_trans_rel = other.bom_trans_rel; refresh_id=other.refresh_id; lift_num = other.lift_num; }
return *this;
}; PyObject* topyfromstruct(data_row & row) { //MessageBox(NULL,"test", "对话框(标题)", MB_OK); return Py_BuildValue("(s, s, s,s,s,s,s,s,s,s,s,s,i)",row.lift_type.c_str(),row.plan_design_finish.c_str(), row.contract_id.c_str(),\ row.project_id.c_str(),row.project_name.c_str(),row.lift_id.c_str(),row.res_engineer.c_str(),row.act_design_finish.c_str(),\ row.prj_distribution.c_str(),row.remarks.c_str(),row.bom_trans_rel.c_str(),row.refresh_id.c_str(),row.lift_num); }; PyObject* topyfromvector(vector & rows) { vector::iterator it; PyObject* pylist=PyList_New(rows.size()); Py_ssize_t i_pos=0; for(it=rows.begin();it!=rows.end();it++,i_pos++) { PyList_SetItem(pylist,i_pos, topyfromstruct(*it)); } //MessageBox(NULL, rows[0].project_id.c_str(), "对话框(标题)", MB_OK); return pylist; } data_row tocppfromtuple(PyObject* pyo) { assert(pyo); data_row row; Py_ssize_t i_size=12; if (PyTuple_Check(pyo)) { if (PyTuple_Size(pyo) == 12) { PyObject * py0=PyTuple_GetItem(pyo,0); if(py0==Py_None) row.lift_type=""; else row.lift_type = CppBuilder()(py0) ; PyObject * py1=PyTuple_GetItem(pyo, 1); if(py1==Py_None) row.plan_design_finish=""; else { row.plan_design_finish = CppBuilder()(py1) ; } PyObject * py2 = PyTuple_GetItem(pyo, 2); if(py2==Py_None) row.contract_id=""; else { row.contract_id = CppBuilder()(py2) ; } PyObject *py3 = PyTuple_GetItem(pyo, 3); if(py3==Py_None) row.project_id=""; else { row.project_id = CppBuilder()(py3) ; } PyObject *py4 = PyTuple_GetItem(pyo, 4); if(py4==Py_None) row.project_name =""; else { row.project_name = CppBuilder()(py4) ; } PyObject *py5 = PyTuple_GetItem(pyo, 5); if(py5==Py_None) row.lift_id=""; else { row.lift_id = CppBuilder()(py5) ; } PyObject* py6 = PyTuple_GetItem(pyo, 6); if(py6==Py_None) row.res_engineer=""; else { row.res_engineer = CppBuilder()(py6) ; } //MessageBox(NULL,row.plan_design_finish.c_str(),"对话框(标题)", MB_OK); PyObject * py7 = PyTuple_GetItem(pyo,7); if(py7==Py_None) row.act_design_finish=""; else row.act_design_finish = CppBuilder ()(py7); PyObject * py8 = PyTuple_GetItem(pyo,8); if(py8==Py_None) row.prj_distribution=""; else row.prj_distribution = CppBuilder ()(py8) ; PyObject *py9 = PyTuple_GetItem(pyo, 9); if(py9==Py_None) row.remarks = ""; else row.remarks =CppBuilder ()(py9) ; PyObject *py10 = PyTuple_GetItem(pyo, 10); if(py10==Py_None) row.bom_trans_rel=""; else row.bom_trans_rel = CppBuilder()(py10); row.lift_num = 1; return row; } else { ostringstream oss; oss << "PyTuple length differs from required one: " << "PyTuple(" << PyTuple_Size(pyo) << ") " << "and required( %d" < tocppfromlist(PyObject * pyo) { assert(pyo); if(PyList_Check(pyo)) { vector rows; data_row row; Py_ssize_t i_rows= PyList_Size(pyo); for(Py_ssize_t i=0;i
vector combine_the_same_section(vector &rows) { vector drv_res; data_row dr_base; size_t i_count = rows.size(); dr_base=rows[0]; int i_units=1; string s_refresh_id; for(size_t i=1;i drv_temp =tocppfromlist(pyo); vector drv_res=combine_the_same_section(drv_temp); // MessageBox(NULL, drv_res[0].lift_id.c_str(), "对话框(标题)", MB_OK); py_res = topyfromvector(drv_res); drv_res.clear(); return py_res; } }
py2cpp.hpp参照https://github.com/dubzzz/Py2Cpp 此项目更改,代码如下,在string转换中增加datetime的转换。
另外如要转换为time_t,需增加到long下面,因为单独加time_t时会报错,long重复定义。
另: Int在python3中已经统一由long代替,故在PyInt_** 全部加入python版本判断。
#ifndef __PY2CPP_HPP__ #define __PY2CPP_HPP__ #include #include #include #include #include #include
if(pyo==Py_None)
return "";
#if PY_MAJOR_VERSION >=3 and PY_MINOR_VERSION >=3 Py_ssize_t size; const char* str { PyUnicode_AsUTF8AndSize(pyo, &size) }; #else long unsigned int size { PyUnicode_GET_DATA_SIZE(pyo) }; // depreciated since 3.3 const char* str { PyUnicode_AS_DATA(pyo) }; // depreciated since 3.3 #endif return std::string(str, size); }else //if(PyDate_Check(pyo)||PyDateTime_Check(pyo) ) { int i_year {PyDateTime_GET_YEAR(pyo) }; int i_month { PyDateTime_GET_MONTH(pyo) } ; int i_day { PyDateTime_GET_DAY(pyo) }; char s_date[16]; sprintf(s_date, "%d-%d-%d", i_year,i_month,i_day); //MessageBox(NULL, s_date, "对话框(标题)", MB_OK); return std::string(s_date); } //throw std::invalid_argument("Not a PyUnicode or PyDateTime instance"); } }; template void _feedCppTuple(TUPLE& tuple, PyObject* root) {} template void _feedCppTuple(TUPLE& tuple, PyObject* root) { std::get(tuple) = CppBuilder()(PyTuple_GetItem(root, pos)); _feedCppTuple(tuple, root); } template struct CppBuilder> { std::tuple operator() (PyObject* pyo) { assert(pyo); if (PyTuple_Check(pyo)) { if (PyTuple_Size(pyo) == sizeof...(Args)) { std::tuple tuple { std::make_tuple(Args()...) }; _feedCppTuple, 0, Args...>(tuple, pyo); return tuple; } else { std::ostringstream oss; oss << "PyTuple length differs from asked one: " << "PyTuple(" << PyTuple_Size(pyo) << ") " << "and std::tuple<...>(" << sizeof...(Args) << ")"; throw std::length_error(oss.str()); } } throw std::invalid_argument("Not a PyTuple instance"); } }; /** * VECTOR has to have the following characteristics: * * (constructor): * VECTOR(size_type count) * build a VECTOR of size count * * ::begin() * ::end() * ::iterator compatible with ++it */ template struct CppBuilder { VECTOR operator() (PyObject* pyo) { assert(pyo); if (PyList_Check(pyo)) { unsigned int i { 0 }; VECTOR v(PyList_Size(pyo)); for (typename VECTOR::iterator it { v.begin() } ; it != v.end() ; ++it, ++i) { *it = CppBuilder()(PyList_GetItem(pyo, i)); } return v; } throw std::invalid_argument("Not a PyList instance"); } }; template struct CppBuilder> { std::set operator() (PyObject* pyo) { assert(pyo); if (PySet_Check(pyo)) { long size { PySet_Size(pyo) }; std::vector backup(size); std::set s; for (long i { 0 } ; i != size ; ++i) { PyObject* popped { PySet_Pop(pyo) }; backup[i] = popped; s.insert(CppBuilder()(popped)); } for (PyObject* popped : backup) { PySet_Add(pyo, popped); Py_DECREF(popped); } return s; } throw std::invalid_argument("Not a PySet instance"); } }; template struct CppBuilder> { std::map operator() (PyObject* pyo) { assert(pyo); if (PyDict_Check(pyo)) { std::map dict; PyObject *key, *value; Py_ssize_t pos = 0; while (PyDict_Next(pyo, &pos, &key, &value)) { dict[CppBuilder()(key)] = CppBuilder()(value); } return dict; } throw std::invalid_argument("Not a PyDict instance"); } }; } } #endif
项目地址: https://github.com/mikewolfli/history_data