代码之家  ›  专栏  ›  技术社区  ›  Mercury

从C++到Python复合体列表列表的元组

  •  0
  • Mercury  · 技术社区  · 5 年前

    我有一个 PyObject* outvar 基本构造为:

    //some defs
    typedef std::complex<double> Pt;
    typedef std::vector<Pt> Pgon;
    typedef std::vector<Pgon> Pgons;
    PyObject* outvar = PyTuple_New(2);
    
    auto outA = pgons2pylist(pA);
    auto outB = pgons2pylist(pB);
    PyTuple_SET_ITEM(outvar, 0, outp);
    PyTuple_SET_ITEM(outvar, 1, outl);
    

    哪里 pgons2pylist

    PyObject* pgons2pylist(const Pgons& data) {
      PyObject* listObj = PyList_New( data.size() );
        for (unsigned int i = 0; i < data.size(); i++) {
            PyList_SET_ITEM(listObj, i, pgon2pylist(data[i]));
        }
        return listObj;
    }
    

    pgon2pylist 是:

    PyObject* pgon2pylist(const Pgon& data) {
      PyObject* listObj = PyList_New( data.size() );
        for (unsigned int i = 0; i < data.size(); i++) {
            PyList_SET_ITEM(listObj, i, PyComplex_FromDoubles(data[i].real(),data[i].imag()));
        }
        return listObj;
    }
    

    我编译它并从运行它 py 文件为:

    mylib = ctypes.cdll.LoadLibrary('./mylib.so')
    out_data = mylib.call(some_args)
    

    但是 out_data 总是一个整数!如何转换为[[复杂]]?

    2 回复  |  直到 5 年前
        1
  •  1
  •   CristiFati    5 年前

    你的组织方式 C 代码,看起来更接近 扩展模块 ( [Python 3]: Extending Python with C or C++ )而不是简单的 动态链接库 . 检查 [SO]: Pass str as an int array to a Python C extended function (extended using SWIG) (@CristiFati's answer) 用于方法之间的比较。

    然后,作为注释,您需要指定 阿格特 再成形 对于导入的函数(这就是 int )检查 [SO]: Python ctypes cdll.LoadLibrary, instantiate an object, execute its method, private variable address truncated 因为如果你不这样做会发生什么。

    还列出 [Python 3]: ctypes - A foreign function library for Python 页。

    关于代码的几个注意事项:

    所以,假设你有工作 动态链接库 ,下面是如何使用它(盲目发布代码):

    mylib = ctypes.pydll.LoadLibrary('./mylib.so')
    outvar = ctypes.py_object.in_dll(mylib, "outvar")  # Note that you might have to declare it as extern "C", so its name doesn't get mangled
    

    @编辑0 :

    我创建了一个虚拟的例子来测试是否一切都正常。

    动态链接库 :

    #include <Python.h>
    
    #if defined(_WIN32)
    #  define EXPORT __declspec(dllexport)
    #else
    #  define EXPORT
    #endif
    
    
    EXPORT PyObject *tp = NULL;
    EXPORT int i = 123;
    EXPORT char *s = "Gainarie";
    EXPORT float f = -3.14;
    
    
    EXPORT void initTpl() {
        tp = PyTuple_New(2);
        PyTuple_SET_ITEM(tp, 0, PyLong_FromLong(7));
        PyTuple_SET_ITEM(tp, 1, PyLong_FromLong(-9));
    }
    

    密码 :

    #!/usr/bin/env python3
    
    import sys
    import ctypes
    
    
    def main():
        dll = ctypes.PyDLL("./dll.so")
        i = ctypes.c_int.in_dll(dll, "i")
        s = ctypes.c_char_p.in_dll(dll, "s")
        f = ctypes.c_float.in_dll(dll, "f")
        dll.initTpl()
        tp = ctypes.py_object.in_dll(dll, "tp")
    
        print(i.value, s.value, f.value, tp.value, type(tp.value))
    
    
    if __name__ == "__main__":
        print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
        main()
    

    笔记 :

    • 我只在 ,因为我没有在 LNX 虚拟机 但这不应该是个问题
    • 因为它只用于演示,所以我不在乎 内存泄漏 (我也没有检查 PyxxRefff 是必要的)

    产量 :

    e:\Work\Dev\StackOverflow\q054429301>dir /b
    code.py
    dll.c
    
    e:\Work\Dev\StackOverflow\q054429301>"c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" x64
    
    e:\Work\Dev\StackOverflow\q054429301>cl /nologo /DDLL /MD /I"c:\Install\x64\Python\Python\03.06.08\include" dll.c  /link /NOLOGO /DLL /LIBPATH:"c:\Install\x64\Python\Python\03.06.08\libs" /OUT:dll.so
    dll.c
       Creating library dll.lib and object dll.exp
    
    e:\Work\Dev\StackOverflow\q054429301>dir /b
    code.py
    dll.c
    dll.exp
    dll.lib
    dll.obj
    dll.so
    
    e:\Work\Dev\StackOverflow\q054429301>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py
    Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32
    
    123 b'Gainarie' -3.140000104904175 (7, -9) <class 'tuple'>
    
        2
  •  1
  •   Damian    5 年前

    我从您的例子中理解,您希望从Python调用C++函数,该函数接受复数列表并返回它们。

    如果你使用 pybind11 您可以免费获得std::vector和std::complex的转换。pybind11是一个只包含头的库。

    下面是一个例子

    实例CPP

    #include <pybind11/pybind11.h>
    #include <pybind11/complex.h>
    #include <pybind11/stl.h>
    
    namespace py = pybind11;
    
    std::complex<double> foo(std::complex<double> a)
    {
        return a;
    }
    
    std::vector<std::complex<double>> foo2(std::vector<std::complex<double>>& v)
    {
        return v;
    }
    
    PYBIND11_MODULE(samplepy, m) {  
        m.def("foo", &foo, "Return the complex number entered as an argument");
        m.def("foo2", &foo2, "Return the list of complex number entered as an argument");
    }
    

    CMAKLISTS.TXT

    cmake_minimum_required (VERSION 3.13)
    project (samplepy CXX)
    set(CMAKE_CXX_STANDARD 17)
    file (GLOB_RECURSE SOURCES "*.cpp" "*.h")
    
    if (WIN32)
        find_package(PythonInterp)
        find_package(PythonLibs 3.6 REQUIRED)
        set(PYBIND11_CPP_STANDARD /std:c++latest)
    else()
        find_package(PythonLibs 3.6 REQUIRED)
        set(PYBIND11_CPP_STANDARD -std=c++1z)
    endif()
    
    add_library (samplepy SHARED ${SOURCES})
    target_link_libraries(samplepy PRIVATE ${PYTHON_LIBRARIES})
    set_target_properties(samplepy PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" SUFFIX "${PYTHON_MODULE_EXTENSION}")
    
    include_directories(${CMAKE_SOURCE_DIR}/include)
    include_directories(${PYTHON_INCLUDE_DIR})
    

    实例

    import samplepy
    z = complex(2, -3)
    print(type(samplepy.foo(z)))
    print(samplepy.foo(z))
    
    l = [complex(1, -2), complex(3, -4)]
    print(type(samplepy.foo2(l)))
    print(samplepy.foo2(l))
    

    当我运行这个时,我在py控制台上得到这个

    <class 'complex'>
    (2-3j)
    <class 'list'>
    [(1-2j), (3-4j)]