gpt4 book ai didi

python - 使用C++项目(Visual Studio)中的参数调用Python函数

转载 作者:搜寻专家 更新时间:2023-10-31 02:08:05 24 4
gpt4 key购买 nike

我需要从Windows平台下的C++项目中调用以Python(3.6)功能实现的管道。文件“ Experiment_test.py ”中的函数“ function_name ”将文本字符串作为输入参数,并返回另一个文本字符串作为结果。我尝试使用以下代码,但无法正常运行-库 shutil 编解码器 makedirs 等库中的python函数无法正常工作。

C++代码(精简版):

std::string Text,Result;
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;
Py_Initialize();

pName = PyUnicode_FromString("experiment_test");
pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);

pFunc = PyDict_GetItemString(pDict, "function_name");

pArgs = PyTuple_New(1);
pValue = PyUnicode_FromString(Text.c_str());
PyTuple_SetItem(pArgs, 0, pValue);

if (PyCallable_Check(pFunc))
{
pValue = PyObject_CallObject(pFunc, pArgs);
if (pValue != NULL)
{
Result = PyUnicode_AsUTF8(pValue);
Py_DECREF(pValue);
}
else return false;
}
// ...

Py_Finalize();

Python代码(精简版):
#!/usr/local/bin/python3
import shutil
import codecs
from os import makedirs
from os import path
from os import unlink
from subprocess import call

def function_name():

name = 'working_files/current_text'

if not path.exists('working_files'):
makedirs('working_files')
if path.exists('result.txt'):
unlink('result.txt')
with codecs.open(name + '.txt', 'w', encoding='utf-8') as f:
f.write(text)
# ...
return result

因此,Python不会生成任何新文件。我试图通过调用 PyRun_SimpleString(“import shutil”);在C++中导入Python模块。 之后的等Py_Initialize(); ,但没有帮助。

我做错了什么?

最佳答案

我尝试使用给定的intel复制问题,但是这是不可能的,所以我创建了一个小示例(尽可能接近问题中所描述的内容)-也称为[SO]: How to create a Minimal, Reproducible Example (reprex (mcve))(应包含在问题BTW中)
因此,我在这里说明的问题是:

  • C++
  • 加载Python引擎
  • 加载Python模块
  • 从该模块中加载一个函数,该函数:
  • 接收代表文件名
  • 的(字符串)参数
  • 读取文件内容(文本)并返回
  • 如果发生错误,只需返回文件名

  • 调用该函数
  • 获取函数调用结果


  • 我正在使用(在Win 10 x64(10.0.16299.125)上):
  • Python 3.5.4 x64
  • VStudio 2015社区版

  • 该结构包括:
  • VStudio项目/解决方案
  • 源文件(main00.cpp(从main.cpp重命名为,但不想再做所有屏幕截图(包含它)))

  • Python模块(experiment_test.py)
  • 测试文件(test_file.txt)

  • main00.cpp:
    #include <string>
    #include <iostream>

    #if defined(_DEBUG)
    # undef _DEBUG
    # define _DEBUG_UNDEFINED
    #endif
    #include <Python.h>
    #if defined(_DEBUG_UNDEFINED)
    # define _DEBUG
    # undef _DEBUG_UNDEFINED
    #endif

    #define MOD_NAME "experiment_test"
    #define FUNC_NAME "function_name"
    #define TEST_FILE_NAME "test_dir\\test_file.txt"

    using std::cout;
    using std::cin;
    using std::endl;
    using std::string;


    int cleanup(const string &text = string(), int exitCode = 1) {
    Py_Finalize();
    if (!text.empty())
    cout << text << endl;
    cout << "Press ENTER to return...\n";
    cin.get();
    return exitCode;
    }


    int main() {
    char c;
    string fName = TEST_FILE_NAME, result;
    PyObject *pName = NULL, *pModule = NULL, *pDict = NULL, *pFunc = NULL, *pArgs = NULL, *pValue = NULL, *pResult = NULL;
    Py_Initialize();
    pName = PyUnicode_FromString(MOD_NAME);
    if (pName == NULL) {
    return cleanup("PyUnicode_FromString returned NULL");
    }
    pModule = PyImport_Import(pName);
    Py_DECREF(pName);
    if (pModule == NULL) {
    return cleanup(string("NULL module: '") + MOD_NAME + "'");
    }
    pDict = PyModule_GetDict(pModule);
    if (pDict == NULL) {
    return cleanup("NULL module dict");
    }
    pFunc = PyDict_GetItemString(pDict, FUNC_NAME);
    if (pFunc == NULL) {
    return cleanup(string("module '") + MOD_NAME + "' doesn't export func '" + FUNC_NAME + "'");
    }
    pArgs = PyTuple_New(1);
    if (pArgs == NULL) {
    return cleanup("NULL tuple returned");
    }
    pValue = PyUnicode_FromString(fName.c_str());
    if (pValue == NULL) {
    Py_DECREF(pArgs);
    return cleanup("PyUnicode_FromString(2) returned NULL");
    }
    int setItemResult = PyTuple_SetItem(pArgs, 0, pValue);
    if (setItemResult) {
    Py_DECREF(pValue);
    Py_DECREF(pArgs);
    return cleanup("PyTuple_SetItem returned " + setItemResult);
    }
    pResult = PyObject_CallObject(pFunc, pArgs);
    Py_DECREF(pArgs);
    Py_DECREF(pValue);
    if (pResult == NULL) {
    return cleanup("PyObject_CallObject returned NULL");
    } else {
    int len = ((PyASCIIObject *)(pResult))->length;
    char *res = PyUnicode_AsUTF8(pResult);
    Py_DECREF(pResult);
    if (res == NULL) {
    return cleanup("PyUnicode_AsUTF8 returned NULL");
    } else {
    cout << string("C(++) - Python call: ") << MOD_NAME << "." << FUNC_NAME << "('" << fName << "') returned '" << res << "' (len: " << len << ")" << endl;
    }
    }
    return cleanup("OK", 0);
    }
    注释:
  • 开头的_DEBUG/_DEBUG_UNDEFINED东西-在 Debug模式下构建时(与python35_ .lib相对),一种(lam)解决方法(gainarie)可以链接到Release Python lib(python35.lib)。
  • 正如我所说,试图简化代码(摆脱了PyCallable_Check测试)
  • 尽管它使用了 C++ 编译器,但很容易注意到该代码是以 C 样式编写的
  • 由于Python API([Python.Docs]: Embedding Python in Another Application)(扩展/嵌入)都使用指针,因此请确保测试NULL的,否则很有可能出现段错误(访问冲突)
  • 添加了[Python.Docs]: Reference Counting - void Py_DECREF(PyObject *o)语句以避免内存泄漏
  • Build(编译/链接)/Run选项(显然,您已经过去了,因为您能够运行程序,但是我还是要列出它们-确保在处理时这里有一些快捷方式。)比一个这样的项目):
  • 检查[SO]: LNK2005 Error in CLR Windows Form (@CristiFati's answer)以了解构建Win PE
  • 的详细信息
  • 为了加快构建依赖Python的项目时的速度,我创建了一个VStudio用户宏(称为Python35Dir-如下图所示,指向我的Python 3.5安装目录)

  • macros
    注释:
  • 路径(“c:\Install\x64\Python\Python\3.5”)指向从官方站点下载的安装
  • 显然,对于32位,必须相应地设置路径(至32位Python)
  • 此路径包含(按预期的方式)一个发行版,并且只要我不需要进入Python代码(并且只要我不弄乱内存,就像(在构建我的应用时, Debug模式)我的.exe中有2个C运行时-检查下面的链接,了解篡改MSVC运行时(UCRT)会发生什么情况:
  • [SO]: When using fstream in a library I get linker errors in the executable (@CristiFati's answer)
  • [SO]: Errors when linking to protobuf 3 on MS Visual C (@CristiFati's answer)
  • 对于特殊情况,我已经在Debug模式下构建了Python并获得了二进制文件,但这不是我的第一选择,因为它需要更改设置(路径)

  • 编译:
    让VStudio知道Python包含文件的位置:
    include
  • 链接:
    让VStudio知道Python库文件的位置(如果只需要pythonxx * .lib( PYTHONCORE ),则不需要额外的操作,因为Python代码默认包含PYTHONCORE;否则,应在[MS.Docs]: .Lib Files as Linker Input中指定所有其余内容:
    link
  • 运行/调试-让:
  • VStudio知道Python运行时 python35.dll (PYTHONCORE)的位置(%PATH%)
  • 已加载的Python运行时知道附加模块的位置(%PYTHONPATH%)

  • debug


    Experiment_test.py:
    import os
    import shutil
    import codecs


    def function_name(file_name):
    print("Py - arg: '{}'".format(file_name))
    if not os.path.isfile(file_name):
    return file_name
    with open(file_name, "rb") as f:
    content = f.read().decode()
    print("Py - Content len: {}, Content (can spread across multiple lines): '{}'".format(len(content), content))
    return content
    注释:
  • 开头指定的几乎是虚拟的模块
  • 仅与文本文件一起使用(二进制文件解码失败)
  • 导入未使用的模块,以查看它们是否正常(很明显,如果这样的导入语句成功,则所有模块都应如此)
  • 在stdout上打印一些数据(与C++端的内容匹配)
  • 位于Python已知的路径(上一步中的%PYTHONPATH%)
  • 有1个参数(file_name)-关键差异与该问题中没有任何参数(不知道这是逻辑错误还是像错字一样)

  • test_dir\test_file.txt:
    line 0 - dummy
    line 1 - gainarie
    输出(VStudio控制台):

    Py - arg: 'test_dir\test_file.txt'
    Py - Content len: 33, Content (can spread across multiple lines): 'line 0 - dummy
    line 1 - gainarie'
    C(++) - Python call: experiment_test.function_name('test_dir\test_file.txt') returned 'line 0 - dummy
    line 1 - gainarie' (len: 33)
    OK
    Press ENTER to return...

    最后备注:
  • 在这种情况下(简单的一种),使用安装路径中的PYTHONCORE。但是在其他版本中(例如,在另一产品中附带的版本),必须在Py_Initialize之前通过Py_SetPythonHome 设置 Python的标准库路径。虽然很旧,但[SO]: What files are required for Py_Initialize to run? (@CristiFati's answer)可能包含一些有用的信息
  • 关于python - 使用C++项目(Visual Studio)中的参数调用Python函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47942845/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com