天天看點

Python&C++互相混合調用程式設計全面實戰-19c++給python傳遞函數和自定義子產品

作者:虛壞叔叔

早餐店不會開到晚上,想吃的人早就來了!😄

c++給python傳遞函數和自定義子產品

Python&C++互相混合調用程式設計全面實戰-19c++給python傳遞函數和自定義子產品

一、傳遞函數

​python​

​​端的​

​test.py​

​添加一個函數的調用:

Python&C++互相混合調用程式設計全面實戰-19c++給python傳遞函數和自定義子產品

在​

​C++​

​端首先需要添加一個函數指針

static PyObject *test_cfun(PyObject *self, PyObject *args)
{
  cout << "in c++ test_cfun function" << endl;
  Py_RETURN_TRUE;
}      

然後添加對函數的定義:以及函數的調用:

// 給 Python 傳遞函數
    PyMethodDef cfuns[] = {
      {"test_cfun", test_cfun, METH_VARARGS, 0},
      {NULL}
    };
    PyModule_AddFunctions(m, cfuns);      

運作代碼:

Python&amp;C++互相混合調用程式設計全面實戰-19c++給python傳遞函數和自定義子產品

二、讀取python子產品并給python主子產品傳遞子產品

2.1傳遞實戰

定義一個​

​python​

​​子產品​

​testmod.py​

​:

print("Test Mod In python")

def testmod():
    print("testmod function in testmod.py")      
Python&amp;C++互相混合調用程式設計全面實戰-19c++給python傳遞函數和自定義子產品

在​

​c++​

​中導入子產品,并将這個子產品添加到主子產品:

// 給 python 傳遞子產品
    // 讀取子產品(腳本檔案直接當作子產品)
    PyObject *testmod = PyImport_ImportModule("testmod"); //相當于python裡面的import testmod
    if (!testmod)
    {
      throw exception("PyImport_ImportModule testmod failed");
    }

    // 将子產品傳給python的主子產品
    PyModule_AddObject(m, "testmod", testmod);      

在​

​test.py​

​​中調用傳遞進來的​

​testmod​

​子產品的函數:

# c傳遞過來的子產品
testmod.testmod()      

2.2 傳遞子產品用處

三、完整代碼

#include <iostream>
#include <Python.h>
#include <exception>
using namespace std;

static PyObject *test_cfun(PyObject *self, PyObject *args)
{
  cout << "in c++ test_cfun function" << endl;
  Py_RETURN_TRUE;
}

int main(int argc, char*argv[])
{
  cout << "C++ call Python" << endl;

  // 設定Python的Home路徑
  Py_SetPythonHome(L"./");

  // Python初始化解釋器
  Py_Initialize();

  PyObject *m = NULL; // 主子產品
  try
  {
    int re = 0;
    // 執行Python腳本
    re = PyRun_SimpleString("print('Hello world!')");
    re = PyRun_SimpleString("print(\"__name__ = \", __name__)");

    // 擷取主子產品
    PyObject *key = PyUnicode_FromString("__main__");
    m = PyImport_GetModule(key); // 不清理參數,需要手動清理
    Py_XDECREF(key);

    // 傳遞位置要在python代碼調用之前
    // 給python傳遞 變量、函數、類、子產品(讀取一個python子產品傳遞給主子產品)
    // 傳遞變量(隻能傳給主子產品__main__)
    PyRun_SimpleString("a=888");

    // 支援傳遞其他非_main__子產品,空間轉給python管理
    PyObject_SetAttrString(m, "count", PyLong_FromLong(777));

    // 給 Python 傳遞函數
    PyMethodDef cfuns[] = {
      {"test_cfun", test_cfun, METH_VARARGS, 0},
      {NULL}
    };
    PyModule_AddFunctions(m, cfuns);

    // 給 python 傳遞子產品
    // 讀取子產品(腳本檔案直接當作子產品)
    PyObject *testmod = PyImport_ImportModule("testmod"); //相當于python裡面的import testmod
    if (!testmod)
    {
      throw exception("PyImport_ImportModule testmod failed");
    }

    // 将子產品傳給python的主子產品
    PyModule_AddObject(m, "testmod", testmod);

    // 執行Python檔案
    char* filename = "test.py";
    FILE * fp = fopen(filename, "r");
    if (!fp)
    {
      throw exception("open file failed");
    }
    PyRun_AnyFile(fp, filename);
    if (re != 0)
    {
      PyErr_Print();
      throw exception("PyRun_AnyFile failed");
    }

    // 2-1 調用python的變量 python做配置檔案
    //con = {
    //  "width":1920,
    //  "heigth" : 1080,
    //  "title" : "C++ call Python"
    //}
    {
      // 根據子產品和名稱擷取對象(對象可以是變量、函數和類)
      PyObject* conf = PyObject_GetAttrString(m, "conf");
      if (!conf) {
        throw exception("conf noe find!");
      }
      PyObject *key = PyUnicode_FromString("width");
      int width = PyLong_AsLong(PyDict_GetItem(conf, key));
      Py_XDECREF(key);

      key = PyUnicode_FromString("height");
      int height = PyLong_AsLong(PyDict_GetItem(conf, key));
      Py_XDECREF(key);

      key = PyUnicode_FromString("title");
      wchar_t title[1024] = { 0 };
      int size = PyUnicode_AsWideChar(PyDict_GetItem(conf, key), title, 1023);
      Py_XDECREF(key);

      printf("width=%d height=%d \n", width, height);
      wprintf(L"title=%s\n", title);

      Py_XDECREF(conf);
    }


    {
      // 擷取類
      PyObject* TypePy = PyObject_GetAttrString(m, "TypePy");
      if (!TypePy) {
        throw exception("TypePy noe find!");
      }
      // 執行個體化對象 相當于調用構造函數__init__ 傳遞構造函數的參數NULL
      PyObject *obj = PyObject_CallObject(TypePy, NULL);
      if (!obj) {
        throw exception("obj not Create!");
      }

      // 調用類成員函數 i(int) s(string)
      PyObject *re = PyObject_CallMethod(obj, "test", "is", 2001, "c Para2");
      cout << "PyObject_CallMethod return" << PyLong_AsLong(re) << endl;
      Py_XDECREF(re);

      // 通路成員變量
      PyObject* var = PyObject_GetAttrString(obj, "id");
      cout << "TypePy.id=" << PyLong_AsLong(var) << endl;
      Py_XDECREF(var);

      Py_XDECREF(obj);
      Py_XDECREF(TypePy);
    }

    {
      // C++調用Python函數
      PyObject* Main = PyObject_GetAttrString(m, "Main");
      if (Main && PyCallable_Check(Main)) {
        // 函數對象和參數 傳回對象
        if (!PyObject_CallObject(Main, 0))
        {
          throw exception("PyObject_CallObject Failed");
        }
      }
      Py_XDECREF(Main);

      // c++調用Python的函數 list參數和list傳回值
      PyObject* TestFun = PyObject_GetAttrString(m, "TestFun");
      if (TestFun && PyCallable_Check(TestFun)) {
        // 參數準備 參數變量是tuple
        PyObject *args = PyTuple_New(1); // 參數是元組 隻有元組這個一個參數
                         // 傳遞的list對象
        PyObject *lis = PyList_New(0);
        for (int i = 0; i < 5; i++)
          PyList_Append(lis, PyLong_FromLong(i + 100));
        // 将list寫入元組參數清單中
        PyTuple_SetItem(args, 0, lis);
        // 函數對象和參數的傳回值
        PyObject* re = PyObject_CallObject(TestFun, args);
        Py_XDECREF(args); // lis也在args中銷毀

                  // 處理傳回值
        if (re)
        {
          cout << "PyObject_CallObject return" << endl;
          int size = PyList_Size(re);
          for (int i = 0; i < size; i++)
          {
            PyObject *val = PyList_GetItem(re, i);
            if (!val)
              continue;
            printf("[%d]", PyLong_AsLong(val));
          }
          Py_XDECREF(re);
        }

      }
      Py_XDECREF(TestFun);
    }


    Py_XDECREF(m);
    // 清理python
    Py_Finalize();
  }
  catch (const std::exception&ex)
  {
    cout << ex.what() << endl;// 清理python
    Py_XDECREF(m);
    Py_Finalize();
  }

  getchar();
  return 0;
}      

四、總結

  • 本文講解了c++給python傳遞函數和自定義子產品 。