how to deal with the PyObject* from C++ in Python

2019-02-11 09:05发布

问题:

I create DLL wrote in C++ , the exporting function returns PyObject * .Then I use ctypes to import the DLL in Python . Now , how can I get the real PyObject ??

here's some part of c++ code:

PyObject* _stdcall getList(){

    PyObject * PList = NULL;
    PyObject * PItem = NULL;
    PList = PyList_New(10);

    vector <int> intVector;
    int i;
    for(int i=0;i<10;i++){
        intVector.push_back(i);
    }

    for(vector<int>::const_iterator it=intVector.begin();it<intVector.end();it++){
        PItem = Py_BuildValue("i", &it);
        PyList_Append(PList, PItem);
    }
    return PList;
}

and some python code :

dll = ctypes.windll.LoadLibrary(DllPath)
PList = dll.getList()

*I wanna get the real python list containing 1,2,3,4...10 ? * Am I clear ?? Thanks advance

回答1:

You have a number of issues of your code, some modifications:

#include <Python.h>
#include <vector>

extern "C" PyObject* _stdcall getList(){
  PyObject *PList = PyList_New(0);

  std::vector <int> intVector;
  std::vector<int>::const_iterator it;

  for(int i = 0 ; i < 10 ; i++){
    intVector.push_back(i);
  }

  for(it = intVector.begin(); it != intVector.end() ; it++ ){
    PyList_Append(PList, Py_BuildValue("i", *it));
  }

  return PList;
}

compile it:

> g++ -Wall -shared lib.cpp -I \Python27\include -L \Python27\libs -lpython27 -o lib.dll -Wl,--add-stdcall-alias

now you can load it as any function and set the getList return type to py_object as:

import ctypes

lib = ctypes.WinDLL('lib.dll')

getList = lib.getList
getList.argtypes = None
getList.restype = ctypes.py_object

getList()

test it:

>>> import ctypes
>>>
>>> lib = ctypes.WinDLL('lib.dll')
>>>
>>> getList = lib.getList
>>> getList.argtypes = None
>>> getList.restype = ctypes.py_object
>>> getList()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
>>>


回答2:

With Visual Studio, and Python 64 bits:
1- Create an empty Win32 Project (DLL Type)
2- Right Click on your Solution Project -> Configuration Manager
3- Active Solution configuration (Release)
4- Active Solution Platform -> New, then on the bottom Dropdown list, select x64 -> OK
5- In the Source Files Folder, add an empty C++ file
6- Put your C++ code (One modification for getList to be recognized)

#include <Python.h>
#include <vector>

extern "C" __declspec(dllexport) PyObject* _stdcall getList();

PyObject* _stdcall getList(){


    PyObject *PList = PyList_New(0);

    std::vector <int> intVector;
    std::vector<int>::const_iterator it;

    for (int i = 0; i < 10; i++){
        intVector.push_back(i);
    }

    for (it = intVector.begin(); it != intVector.end(); it++){
        PyList_Append(PList, Py_BuildValue("i", *it));
    }

    return PList;
}


回答3:

I'm not exactly clear what you are asking. But I suppose you mean to ask what you can do now with your DLL.

  1. Well, in order to use it appropriately, you'll have to build a special DLL which directly can be imported as a module in Python. In order to determine what to do in order to use this, it is best you have a look for other modules, how they do it. E. g. MySQLdb could be a candidate.

    In short, you have this "wrapper" DLL call your function.

  2. But if I have a second look at your question now, I see that you are trying to load your DLL via ctypes. This is viable as well, maybe even better, and you'll have to use the ctypes.py_object data type.