关于python3调用C/C++的方法(ctypes)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/mikewolfli/article/details/50475035
  转载请注明出处!
     源代码
     最近帮同事做一个历史数据的转换合并软件,使用python3从数据库读出数据,然后根据其中的几个字段相同的归类合并一行,然后输出到EXCEL中,数据大概是5W行,考虑到归类合并逻辑比较复杂,用python效率比较低,这部分用c/c++完成,python3调用生成的dll.
运行截图
关于python3调用C/C++的方法(ctypes) - 迈克暖风 - 上善若水
 
 代码如下:
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 <Python.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <windows.h> #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<data_row> & rows) { vector<data_row>::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<string>()(py0) ; PyObject * py1=PyTuple_GetItem(pyo, 1); if(py1==Py_None) row.plan_design_finish=""; else { row.plan_design_finish = CppBuilder<string>()(py1) ; } PyObject * py2 = PyTuple_GetItem(pyo, 2); if(py2==Py_None) row.contract_id=""; else { row.contract_id = CppBuilder<string>()(py2) ; } PyObject *py3 = PyTuple_GetItem(pyo, 3); if(py3==Py_None) row.project_id=""; else { row.project_id = CppBuilder<string>()(py3) ; } PyObject *py4 = PyTuple_GetItem(pyo, 4); if(py4==Py_None) row.project_name =""; else { row.project_name = CppBuilder<string>()(py4) ; } PyObject *py5 = PyTuple_GetItem(pyo, 5); if(py5==Py_None) row.lift_id=""; else { row.lift_id = CppBuilder<string>()(py5) ; } PyObject* py6 = PyTuple_GetItem(pyo, 6); if(py6==Py_None) row.res_engineer=""; else { row.res_engineer = CppBuilder<string>()(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<string> ()(py7); PyObject * py8 = PyTuple_GetItem(pyo,8); if(py8==Py_None) row.prj_distribution=""; else row.prj_distribution = CppBuilder<string> ()(py8) ; PyObject *py9 = PyTuple_GetItem(pyo, 9); if(py9==Py_None) row.remarks = ""; else row.remarks =CppBuilder<string> ()(py9) ; PyObject *py10 = PyTuple_GetItem(pyo, 10); if(py10==Py_None) row.bom_trans_rel=""; else row.bom_trans_rel = CppBuilder<string>()(py10); row.lift_num = 1; return row; } else { ostringstream oss; oss << "PyTuple length differs from required one: " << "PyTuple(" << PyTuple_Size(pyo) << ") " << "and required( %d" <<i_size << ")"; throw length_error(oss.str()); } } throw invalid_argument("Not a PyTuple instance"); } vector<data_row> tocppfromlist(PyObject * pyo) { assert(pyo); if(PyList_Check(pyo)) { vector<data_row> rows; data_row row; Py_ssize_t i_rows= PyList_Size(pyo); for(Py_ssize_t i=0;i<i_rows;i++) { // MessageBox(NULL, "test", "对话框(标题)", MB_OK); row = tocppfromtuple(PyList_GetItem(pyo, i)); rows.push_back(row); } //MessageBox(NULL, rows[0].project_id.c_str(), "对话框(标题)", MB_OK); return rows; } throw invalid_argument("Not a PyList instance"); }

vector<data_row> combine_the_same_section(vector<data_row> &rows) { vector<data_row> 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<i_count;i++) { if(dr_base.project_id==rows[i].project_id&&dr_base.lift_type==rows[i].lift_type&&dr_base.plan_design_finish==rows[i].plan_design_finish&& dr_base.res_engineer==rows[i].res_engineer&&dr_base.act_design_finish==rows[i].act_design_finish&&dr_base.prj_distribution==rows[i].prj_distribution&& dr_base.bom_trans_rel==rows[i].bom_trans_rel) { dr_base.lift_id=dr_base.lift_id+","+rows[i].lift_id; i_units++; }else { dr_base.refresh_id=dr_base.contract_id+":"+dr_base.project_id+":"+dr_base.project_name+":"+dr_base.lift_id; dr_base.lift_num=i_units; drv_res.push_back(dr_base); dr_base=rows[i]; i_units=1; } } rows.clear(); return drv_res; } extern "C" { // A function adding two integers and returning the result PyObject * combine_list( PyObject * pyo) { assert(pyo); PyObject *py_res; vector<data_row> drv_temp =tocppfromlist(pyo); vector<data_row> 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 <cassert> #include <climits> #include <sstream> #include <stdexcept> #include <typeinfo> #include <map> #include <set> #include <string> #include <tuple> #include <ctime> #include <vector> #include <Python.h> #include <datetime.h> namespace dubzzz { namespace Py2Cpp { template <class T> struct CppBuilder; template <> struct CppBuilder<PyObject*> { PyObject* operator() (PyObject* pyo) { assert(pyo); return pyo; } }; template <> struct CppBuilder<bool> { bool operator() (PyObject* pyo) { assert(pyo); if (PyBool_Check(pyo)) { return pyo == Py_True; } throw std::invalid_argument("Not a PyBool instance"); } }; template <> struct CppBuilder<int> { int operator() (PyObject* pyo) { assert(pyo); if (PyLong_Check(pyo)) { long v { PyLong_AsLong(pyo) }; if (v < INT_MIN || v > INT_MAX) { throw std::overflow_error("Out of <int> boundaries"); } return static_cast<int>(v); } #if PY_MAJOR_VERSION <=2 else if (PyInt_Check(pyo)) { long v { PyInt_AS_LONG(pyo) }; if (v < INT_MIN || v > INT_MAX) { throw std::overflow_error("Out of <int> boundaries"); } return static_cast<int>(v); } #endif // PY_MAJOR_VERSION throw std::invalid_argument("Not a PyLong instance"); } }; template <> struct CppBuilder<unsigned int> { unsigned int operator() (PyObject* pyo) { assert(pyo); if (PyLong_Check(pyo)) { unsigned long v { PyLong_AsUnsignedLongMask(pyo) }; if (v > UINT_MAX) { throw std::overflow_error("Out of <unsigned int> boundaries"); } return static_cast<unsigned int>(v); } #if PY_MAJOR_VERSION <=2 else if (PyInt_Check(pyo)) { unsigned long v { PyInt_AsUnsignedLongMask(pyo) }; if (v > UINT_MAX) { throw std::overflow_error("Out of <unsigned int> boundaries"); } return static_cast<int>(v); } #endif // PY_MAJOR_VERSION throw std::invalid_argument("Not a PyLong instance"); } }; template <> struct CppBuilder<long> { long operator() (PyObject* pyo) { assert(pyo); if (PyLong_Check(pyo)) { return PyLong_AsLong(pyo); } #if PY_MAJOR_VERSION <=2 else if (PyInt_Check(pyo)) { return PyInt_AS_LONG(pyo); } #endif // PY_MAJOR_VERSION /* else if(PyDate_Check(pyo)) { struct tm tim; tim.tm_year = PyDateTime_GET_YEAR(pyo) ; tim.tm_mon = PyDateTime_GET_MONTH(pyo) ; tim.tm_mday = PyDateTime_GET_DAY(pyo) ; std::time_t date_res= mktime(&tim); return date_res; }*/ throw std::invalid_argument("Not a PyLong instance"); } }; template <> struct CppBuilder<unsigned long> { unsigned long operator() (PyObject* pyo) { assert(pyo); if (PyLong_Check(pyo)) { return PyLong_AsUnsignedLong(pyo); } #if PY_MAJOR_VERSION <=2 else if (PyInt_Check(pyo)) { return PyInt_AsUnsignedLongMask(pyo); } #endif // PY_MAJOR_VERSION throw std::invalid_argument("Not a PyLong instance"); } }; template <> struct CppBuilder<long long> { long long operator() (PyObject* pyo) { assert(pyo); if (PyLong_Check(pyo)) { return PyLong_AsLongLong(pyo); } #if PY_MAJOR_VERSION <=2 else if (PyInt_Check(pyo)) { return PyInt_AS_LONG(pyo); } #endif // PY_MAJOR_VERSION throw std::invalid_argument("Not a PyLong instance"); } }; template <> struct CppBuilder<unsigned long long> { unsigned long long operator() (PyObject* pyo) { assert(pyo); if (PyLong_Check(pyo)) { return PyLong_AsUnsignedLongLong(pyo); } #if PY_MAJOR_VERSION <=2 else if (PyInt_Check(pyo)) { return PyInt_AsUnsignedLongLongMask(pyo); } #endif // PY_MAJOR_VERSION throw std::invalid_argument("Not a PyLong instance"); } }; template <> struct CppBuilder<double> { double operator() (PyObject* pyo) { assert(pyo); if (PyFloat_Check(pyo)) { return PyFloat_AS_DOUBLE(pyo); } else if (PyLong_Check(pyo)) { return PyLong_AsDouble(pyo); } #if PY_MAJOR_VERSION <=2 else if (PyInt_Check(pyo)) { return PyInt_AS_LONG(pyo); } #endif // PY_MAJOR_VERSION throw std::invalid_argument("Neither a PyDouble nor a PyLong instance"); } }; template <> struct CppBuilder<std::string> { std::string operator() (PyObject* pyo) { assert(pyo); if (PyUnicode_Check(pyo)) {

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 <class TUPLE, std::size_t pos> void _feedCppTuple(TUPLE& tuple, PyObject* root) {} template <class TUPLE, std::size_t pos, class T, class... Args> void _feedCppTuple(TUPLE& tuple, PyObject* root) { std::get<pos>(tuple) = CppBuilder<T>()(PyTuple_GetItem(root, pos)); _feedCppTuple<TUPLE, pos +1, Args...>(tuple, root); } template <class... Args> struct CppBuilder<std::tuple<Args...>> { std::tuple<Args...> operator() (PyObject* pyo) { assert(pyo); if (PyTuple_Check(pyo)) { if (PyTuple_Size(pyo) == sizeof...(Args)) { std::tuple<Args...> tuple { std::make_tuple(Args()...) }; _feedCppTuple<std::tuple<Args...>, 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 <class VECTOR> 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<typename VECTOR::value_type>()(PyList_GetItem(pyo, i)); } return v; } throw std::invalid_argument("Not a PyList instance"); } }; template <class T> struct CppBuilder<std::set<T>> { std::set<T> operator() (PyObject* pyo) { assert(pyo); if (PySet_Check(pyo)) { long size { PySet_Size(pyo) }; std::vector<PyObject*> backup(size); std::set<T> s; for (long i { 0 } ; i != size ; ++i) { PyObject* popped { PySet_Pop(pyo) }; backup[i] = popped; s.insert(CppBuilder<T>()(popped)); } for (PyObject* popped : backup) { PySet_Add(pyo, popped); Py_DECREF(popped); } return s; } throw std::invalid_argument("Not a PySet instance"); } }; template <class K, class T> struct CppBuilder<std::map<K,T>> { std::map<K,T> operator() (PyObject* pyo) { assert(pyo); if (PyDict_Check(pyo)) { std::map<K,T> dict; PyObject *key, *value; Py_ssize_t pos = 0; while (PyDict_Next(pyo, &pos, &key, &value)) { dict[CppBuilder<K>()(key)] = CppBuilder<T>()(value); } return dict; } throw std::invalid_argument("Not a PyDict instance"); } }; } } #endif

项目地址: https://github.com/mikewolfli/history_data

展开阅读全文

没有更多推荐了,返回首页