环境:vs2019,python-3.7.9
本人目前用c++做一个测试工具,打算加入脚本,首当其冲就是python,后面是java和js,java应该是使用jni,js的话网上看到了个v8,后面有深入再说
配置
首先要装好python环境,然后在右键项目->属性->配置属性->vc++目录:在包含目录添加入python安装位置下的include目录,在库目录中添加python安装位置下的libs目录
本人python安装位置为D:\CodeApp\python\python-3.7,所以包含目录为D:\CodeApp\python\python-3.7\include,库目录为D:\CodeApp\python\python-3.7\libs
在这里要注意活动和平台,平台的版本位数要和python安装的位数一样,python安装如果是32位的,平台要改成win32,运行要用x86。python如果是64位,也是一样
一个简单的运行代码
#include <Python.h>
int main()
{
Py_Initialize();
PyRun_SimpleString("print('hello')");
Py_Finalize();
}
可能的问题 :无法打开python37_d.lib
到上述的libs目录下看,发现没有python37_d.lib文件
这是因为当初安装python时没有勾选下面这个选项
已经安装好的启动安装的程序,点击modify,点击next,勾选上,点击install
出现这个问题,可以点击log file打开日志查看问题
这里说一下,这个问题其实是它需要去访问https://www.python.org/ftp/python/3.8.1/win32/core_d.msi来进行下载和安装,这个网址时外网,所以失败(这个路径和下图的内容使用python3.8.1来演示,python3.7.9已经安装好了,不想重新在弄一遍)
遇到这种问题,去官网下载所需要的文件
选择你的python版本
选择你的安装python的位数,32位还是64位
将.msi文件下载到python安装包存放的目录(本人下载时没有全部下载,一般像是core.msi和core_d.msi两个文件,只需要下载core_d.msi,一般是下载_d.msi结尾,但有个别例外,如果不清楚的可以去查看报错的日志,或者全部下载)
下载好点击跟上面一样点击modify,点击next,勾选,点检install
这时在libs目录下就可以找到python37_d.lib文件
另一种解决办法
将debug改成release,但是这没办法调试,不提倡
运行结果
代码
这代码算是学习中的代码,还没来得及重构(其实是懒),需要的人自行使用,代码最初均来源于网络,后面自己修改
irg3_python.h
#ifndef _IRG3_PYTHON_H_
#define _IRG3_PYTHON_H_
#include <Python.h>
#include<unordered_map>
#include <string>
/*
Py_BuildValue使用举例:
Py_BuildValue("") None
Py_BuildValue("i", 123) 123
Py_BuildValue("iii", 123, 456, 789) (123, 456, 789)
Py_BuildValue("s", "hi") 'hi'
Py_BuildValue("ss", "hello", "world") ('hello', 'world')
Py_BuildValue("s#", "hello", 4) 'hell'
Py_BuildValue("()") ()
Py_BuildValue("(i)", 123) (123,)
Py_BuildValue("(ii)", 123, 456) (123, 456)
Py_BuildValue("(i,i)", 123, 456) (123, 456)
Py_BuildValue("[i,i]", 123, 456) [123, 456]
Py_BuildValue("{s:i,s:i}", "abc", 123, "def", 456) {'abc': 123, 'def': 456}
Py_BuildValue("((ii)(ii)) (ii)", 1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6))
*/
/*
常用的几个解析参数与C类型的对应关系:
s:char*
b:unsigned char
c:char
d:double
f:float
h:short int
i:int
l:long
k:unsigned long
L:long long
K:unsigned long long
*/
class Irg3_Py_Script {
private:
Irg3_Py_Script() {}
public:
struct py_node {
std::string path_; //文件所在路径
std::string file_; //文件名(无后缀)
std::string class_n; //类名
std::vector<std::pair<std::string, void*> >cla_vecs_; //类传递参数
std::string method_; //方法名
std::vector<std::pair<std::string, void *> >met_vecs_; //方法参数
std::vector<std::string> ret_vecs_; //返回值
};
virtual ~Irg3_Py_Script() {}
static Irg3_Py_Script* getInstance() {
static Irg3_Py_Script cus_;
return &cus_;
}
public:
//python要求,传入位任意字符串参数,无返回
bool excute(py_node& node_);
//python要求,传入位任意字符串参数,返回为字符串列表
bool excute_list(py_node& node_);
//传入任意参数,返回为字典类型
bool excute_direct(py_node& node_, std::unordered_map<std::string, std::string>* map_ = nullptr);
//python要求,传入位任意字符串参数,返回为元组(s+i)
int excute_s_i(py_node& node_, char* buf_);
//python要求,传入位s+i,返回为元组(s+i)
int excute_s_i(py_node& node_, const char* msg_, int msg_len_, char* buf_);
private:
void create_args(PyObject* cla_args, std::vector<std::pair<std::string, void*> >& vecs_);
};
#endif
irg3_python.cpp
#include "irg3_python.h"
#include <jni.h>
bool Irg3_Py_Script::excute(Irg3_Py_Script::py_node& node_)
{
Py_Initialize();
//2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
std::string val_;
val_.assign("sys.path.append('").append(node_.path_.c_str()).append("')");
PyRun_SimpleString(val_.c_str());
{
PyObject* pFunc = NULL;
PyObject* pObject = NULL;
pObject = PyImport_ImportModule(node_.file_.c_str()); //注意文件名字大小写
//获取类名
if (node_.class_n != "") {
pObject = PyObject_GetAttrString(pObject, node_.class_n.c_str()); //先获取类名
// 定义变量
PyObject* cla_args = PyTuple_New(node_.cla_vecs_.size());
create_args(cla_args, node_.cla_vecs_);
pObject = PyEval_CallObject(pObject, cla_args); //根据类名实例化对象
}
//获取函数
pFunc = PyObject_GetAttrString(pObject, node_.method_.c_str());
PyObject* met_args = PyTuple_New(node_.met_vecs_.size());
create_args(met_args, node_.met_vecs_);
//函数调用
PyObject* pyValue = PyEval_CallObject(pFunc, met_args);
}
Py_Finalize();
return true;
}
bool Irg3_Py_Script::excute_list(Irg3_Py_Script::py_node&node_)
{
Py_Initialize();
bool flag_ = false;
//2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
std::string val_;
val_.assign("sys.path.append('").append(node_.path_.c_str()).append("')");
PyRun_SimpleString(val_.c_str());
{
PyObject* pFunc = NULL;
PyObject* pObject = NULL;
pObject = PyImport_ImportModule(node_.file_.c_str()); //注意文件名字大小写
//获取类名
if (node_.class_n != "") {
pObject = PyObject_GetAttrString(pObject, node_.class_n.c_str()); //先获取类名
// 定义变量
PyObject* cla_args = PyTuple_New(node_.cla_vecs_.size());
create_args(cla_args, node_.cla_vecs_);
pObject = PyEval_CallObject(pObject, cla_args); //根据类名实例化对象
}
//获取函数
pFunc = PyObject_GetAttrString(pObject, node_.method_.c_str());
PyObject* met_args = PyTuple_New(node_.met_vecs_.size());
create_args(met_args, node_.met_vecs_);
//函数调用
PyObject* pyValue = PyEval_CallObject(pFunc, met_args);
//获取结果
if (pyValue&& PyList_Check(pyValue)){
for (Py_ssize_t i = 0; i < PyList_Size(pyValue); ++i) {
char* p = nullptr;
PyObject* next = PyList_GetItem(pyValue, i);
PyArg_Parse(next, "s", &p);
if(p!=nullptr)
node_.ret_vecs_.push_back(p);
}
flag_ = true;
}
}
Py_Finalize();
return flag_;
}
int Irg3_Py_Script::excute_s_i(Irg3_Py_Script::py_node&node_,char*buf_)
{
Py_Initialize();
//2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
std::string val_;
val_.assign("sys.path.append('").append(node_.path_.c_str()).append("')");
PyRun_SimpleString(val_.c_str());
{
PyObject* pFunc = NULL;
PyObject* pObject = NULL;
pObject = PyImport_ImportModule(node_.file_.c_str()); //注意文件名字大小写
//获取类名
if (node_.class_n != "") {
pObject = PyObject_GetAttrString(pObject, node_.class_n.c_str()); //先获取类名
// 定义变量
PyObject* cla_args = PyTuple_New(node_.cla_vecs_.size());
create_args(cla_args, node_.cla_vecs_);
pObject = PyEval_CallObject(pObject, cla_args); //根据类名实例化对象
}
//获取函数
pFunc = PyObject_GetAttrString(pObject, node_.method_.c_str());
//构建参数
PyObject* met_args = PyTuple_New(node_.met_vecs_.size());
create_args(met_args, node_.met_vecs_);
//函数调用
PyObject* pyValue = PyEval_CallObject(pFunc, met_args);
//获取结果
if (pyValue) {
char* val_str_;
int val_len_;
PyArg_ParseTuple(pyValue, "(s,i)", &val_str_, &val_len_);
if (val_str_ == nullptr) {
return -1;
}
memcpy(val_str_, buf_, val_len_);
return val_len_;
}
}
Py_Finalize();
return -1;
}
int Irg3_Py_Script::excute_s_i(Irg3_Py_Script::py_node&node_, const char* msg_, int msg_len_, char* buf_)
{
int ret_val_ = -1;
Py_Initialize();
//2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
std::string val_;
val_.assign("sys.path.append('").append(node_.path_.c_str()).append("')");
PyRun_SimpleString(val_.c_str());
do{
PyObject* pFunc = NULL;
PyObject* pObject = NULL;
pObject = PyImport_ImportModule(node_.file_.c_str()); //注意文件名字大小写
//获取函数
pFunc = PyObject_GetAttrString(pObject, node_.method_.c_str());
PyObject* met_args = PyTuple_New(2);
PyTuple_SetItem(met_args, 0, Py_BuildValue("s", msg_));
PyTuple_SetItem(met_args, 1, Py_BuildValue("i", msg_len_));
//函数调用
PyObject* pyValue = PyEval_CallObject(pFunc, met_args);
//获取结果
if (pyValue) {
char* val_str_;
PyArg_ParseTuple(pyValue, "si", &val_str_, &ret_val_);
if (val_str_ == nullptr) {
break;
}
memcpy(buf_, val_str_, ret_val_);
}
} while (false);
Py_Finalize();
return ret_val_;
}
void Irg3_Py_Script::create_args(PyObject* args_, std::vector<std::pair<std::string, void*> >&vecs_)
{
for (int i = 0; i < vecs_.size(); i++) {
auto& p = vecs_.at(i);
if (p.first[0] == 'i') {
//int整形
PyTuple_SetItem(args_, i, Py_BuildValue(p.first.c_str(), *((int*)p.second)));
}
else if (p.first[0] == 's') {
//std::string字符串
PyTuple_SetItem(args_, i, Py_BuildValue(p.first.c_str(), (char*)p.second));
}
else if (p.first[0] == 'd') {
//double浮点型
PyTuple_SetItem(args_, i, Py_BuildValue(p.first.c_str(), *((double*)p.second)));
}
else if (p.first[0] == 'l') {
//std::vector<std::string>字符串列表
PyObject* pyParams = PyList_New(0); //初始化一个列表
std::vector<std::string>* val_ = (std::vector<std::string> *)p.second;
for (auto& t : *val_) {
PyList_Append(pyParams, Py_BuildValue("s", t.c_str()));
}
PyTuple_SetItem(args_, 0, pyParams);// 变量格式转换成python格式
}
}
}
bool Irg3_Py_Script::excute_direct(Irg3_Py_Script::py_node& node_, std::unordered_map<std::string, std::string>*map_) {
bool ret_flag = false;
Py_Initialize();
//2、初始化python系统文件路径,保证可以访问到 .py文件
PyRun_SimpleString("import sys");
std::string val_;
val_.assign("sys.path.append('").append(node_.path_.c_str()).append("')");
PyRun_SimpleString(val_.c_str());
do {
PyObject* pFunc = NULL;
PyObject* pObject = NULL;
pObject = PyImport_ImportModule(node_.file_.c_str()); //注意文件名字大小写
if (pObject == nullptr) {
break;
}
//获取函数
pFunc = PyObject_GetAttrString(pObject, node_.method_.c_str());
if (pFunc == nullptr) {
break;
}
PyObject* met_args = PyTuple_New(node_.met_vecs_.size());
create_args(met_args, node_.met_vecs_);
//函数调用
PyObject* pyValue = PyEval_CallObject(pFunc, met_args);
//获取结果
if (pyValue) {
PyObject* items = PyMapping_Items(pyValue);
if (items == nullptr) {
break;
}
PyObject* item = nullptr;
int len = PyMapping_Length(items);
const char* key;
const char* val;
for (int i = 0; i < len; i++) {
item = PySequence_GetItem(items, i);
PyArg_ParseTuple(item, "ss", &key, &val);
if (map_ != nullptr) {
(*map_)[key] = val;
}
Py_DECREF(item);
}
Py_DECREF(items);
ret_flag = true;
}
} while (false);
Py_Finalize();
return ret_flag;
}
main.cpp
#include"irg3_python.h"
// 测试
int main(int argc, char* argv[]) {
Irg3_Py_Script::py_node node;
node.file_ = "1";
node.path_ = "d:/test_2";
node.method_ = "method";
char buf[] = "hello";
node.met_vecs_.push_back({ "s",buf });
Irg3_Py_Script::getInstance()->excute(node);
return 0;
}
1.py
def method(name):
print(name)
附录
PyArg_ParseTuple与Py_BuildValue常用的几个解析参数与C类型的对应关系
s:char*
b:unsigned char
c:char
d:double
f:float
h:short int
i:int
l:long
k:unsigned long
L:long long
K:unsigned long long