Python 是一種語法簡潔、功能強大的解釋型程式語言,擁有高效的高層資料結構,並原生支援物件導向程式設計。它既適合快速應用開發,也能勝任大型商業級專案的構建。Python 免費開源、跨平台可移植,只要避免使用作業系統專屬特性,程式碼即可在各主流平台無縫運行。
Python 標準庫極其龐大,涵蓋圖形介面、檔案處理、多媒體、正則表達式、單元測試、多執行緒、資料庫、網路通訊、Web 瀏覽、CGI、FTP、電子郵件、XML/HTML 解析、密碼系統等領域。除了標準庫,還有 wxPython、Twisted、Python 圖形庫等大量高質量第三方庫可用。
在某 C++ 應用中,我們使用插件機制實現統一介面功能。為了避免需求變更時頻繁重新編譯動態連結庫,決定以 Python 腳本替代傳統 DLL 插件。雖然 Python 功能強大,但部分作業系統底層操作仍需 C++ 實現再供 Python 調用。因此核心需求有二:
以下 API 為實戰中常用子集,詳細說明請參考官方文檔。
在 Visual Studio 中建立主控台專案,包含 <Python.h>,並在 main 函式中編寫程式碼。
// 定義常用變數
char *cstr;
PyObject *pstr, *pmod, *pdict;
PyObject *pfunc, *pargs;
__main__ 命名空間執行 Python 程式碼片段。
PyRun_SimpleString("from time import time,ctime\n"
"print 'Today is',ctime(time())\n");
mymod.py),相當於 __import__()。__dict__)。o.attr_name)。為減少樣板程式碼,文中提供 CSimplepy 類別封裝常用操作:
#include "simplepy.h"
CSimplepy py;
py.ImportModule("mymod");
std::string str = py.CallObject("transform",
"this is hjs's test, to uppercase");
printf("%s\n", str.c_str());
建立 Win32 DLL 專案 pyUtil,核心程式碼如下:
// pyUtil.cpp
#include <windows.h>
#include <string>
#include <Python.h>
std::string Recognise_Img(const std::string url) {
return "從dll中返回的數據... : " + url;
}
static PyObject* Recognise(PyObject *self, PyObject *args) {
const char *url;
if (!PyArg_ParseTuple(args, "s", &url)) return NULL;
std::string sts = Recognise_Img(url);
return Py_BuildValue("s", sts.c_str());
}
static PyMethodDef AllMyMethods[] = {
{"Recognise", Recognise, METH_VARARGS},
{NULL, NULL}
};
extern "C" __declspec(dllexport) void initpyUtil() {
Py_InitModule("pyUtil", AllMyMethods);
}
Python 端呼叫:
import pyUtil
result = pyUtil.Recognise("input url of specific data")
print "the result is: " + result
若引入 Boost.Python,同樣功能只需極少程式碼(需連結 boost_python.lib、執行期需 boost_python.dll):
#include <string>
#include <boost/python.hpp>
using namespace boost::python;
#pragma comment(lib, "boost_python.lib")
std::string strtmp;
char const* Recognise(const char* url) {
strtmp = "從dll中返回的數據... : ";
strtmp += url;
return strtmp.c_str();
}
BOOST_PYTHON_MODULE(pyUtil) {
def("Recognise", Recognise);
}
Doc\Python24.chm)this is test text in text.txt.
import string
message = 'original string'
message = message + message
msg_error = ""
try:
text_file = open("text.txt", "r")
whole_thing = text_file.read()
print whole_thing
text_file.close()
except IOError, (errno, strerror):
print "I/O error(%s): %s" % (errno, strerror)
def transform(input):
return string.upper(input)
def change_msg(nul):
global message
message = 'string changed'
return message
def r_file(nul):
return whole_thing
def get_msg(nul):
return message
#ifndef _SIMPLEPY_H_
#define _SIMPLEPY_H_
#include <string>
using std::string;
#include <Python.h>
class CSimplepy {
public:
CSimplepy() {
Py_Initialize();
pstr=pmod=pdict=pfunc=pargs=NULL;
}
virtual ~CSimplepy() { Py_Finalize(); }
bool ImportModule(const char* mod_name) {
try {
pmod = PyImport_ImportModule(const_cast<char*>(mod_name));
if(!pmod) return false;
pdict = PyModule_GetDict(pmod);
} catch(...) { return false; }
return pmod && pdict;
}
int Run_SimpleString(const char* str) {
return PyRun_SimpleString(const_cast<char*>(str));
}
string Run_String(const char* str) {
char *cstr;
pstr = PyRun_String(str, Py_eval_input, pdict, pdict);
if(!pstr) throw "Run_String exception";
PyArg_Parse(pstr, "s", &cstr);
return string(cstr);
}
string CallObject(const char* func_name, const char* parameter) {
pfunc = PyObject_GetAttrString(pmod, const_cast<char*>(func_name));
if(!pfunc) throw (string("not found: ")+func_name).c_str();
pargs = Py_BuildValue("(s)", const_cast<char*>(parameter));
pstr = PyEval_CallObject(pfunc, pargs);
if(!pstr) throw "PyEval_CallObject exception";
char* cstr;
PyArg_Parse(pstr, "s", &cstr);
return string(cstr);
}
protected:
PyObject *pstr, *pmod, *pdict, *pfunc, *pargs;
};
#endif