我如何在Python中使用C++类?

Pra*_*are 34 c++ python class

我用C++实现了一个类.我想在Python中使用它. 请建议一步一步的方法,并详细说明每一步. 这样的事......

class Test{
     private:
        int n;
     public:
        Test(int k){
            n=k;
        }
        void setInt(int k){
            n = k; 
        }
        int getInt(){
            return n;
        }
};
Run Code Online (Sandbox Code Playgroud)

现在,在Python中

>>> T1 = Test(12)
>>> T1.getInt()
12
>>> T1.setInt(32)
>>> T1.getInt()
32
Run Code Online (Sandbox Code Playgroud)

请建议.我怎么能这样做?注意:我想知道手动方式来做到这一点.我不希望任何第三方库依赖.

Joh*_*itb 26

看看Boost.Python.这是一个用C++编写python模块的库.

另请参阅SWIG,它还可以处理其他脚本语言的模块.我以前用它来为我的类编写模块并在python中使用它们.效果很好.

您可以使用Python/C API手动完成,自己编写接口.这是非常低级的,但你将获得许多关于Python如何在幕后工作的额外知识(无论如何你将需要它).

  • 不符合"我不想要任何第三方库依赖"的要求. (14认同)
  • 无论如何你将需要python库.它当然包括python/c api. (2认同)

dan*_*gph 10

ctypes很好.它非常易于使用,并且标配Python.不幸的是,它只能与具有C风格接口的共享库(Unix)或DLL(Windows)通信,这意味着您无法直接连接到C++对象.但是您可以使用句柄系统,其中句柄指的是特定对象.

>>> getInt(h)
12
Run Code Online (Sandbox Code Playgroud)

我认为这很简单,易于理解,并且不需要额外的库.

  • @ 2g7hgfdr8324,你错误引用了我的话.我没有说"你不能谈论共享库或DLL".我反过来说了.是的,如果您可以将C++ API公开为DLL,那么您可以通过ctypes从Python调用它.你的界面必须是普通的C,而不是C++. (4认同)
  • 您能否详细说明一下“您无法与共享库或 DLL 通信,这意味着您无法直接与 C++ 对象交互”是什么意思?在 Python 中使用 C++ 对象时,行为会发生哪些变化?会有明显的影响吗?我最终需要用 Python 编写一个到我的 C++ API 的绑定,提前感谢您的帮助。 (2认同)

Mar*_*rtí 10

这是一篇非常古老的帖子,可能OP已经找到了解决他的问题的方法,但由于还没有人提供有效的例子,我会尝试一下,也许可以帮助像我这样遇到同样问题的人。

由于OP没有指定,我将把我的答案限制在Windows上,尽管Linux解决方案会很简单。我将尝试提供一个最小的工作示例来重现相关代码。

步骤 1) 从 C++ 代码开始(单个文件)

class Test{
     private:
        int n;
     public:
        Test(int k){
            n=k;
        }
        void setInt(int k){
            n = k;
        }
        int getInt(){
            return n;
        }
};

extern "C" 
{
    // include below each method you want to make visible outside
    __declspec(dllexport) Test* init(int k) {return new Test(k);}
    __declspec(dllexport) void setInt(Test *self, int k) {self->setInt(k);}
    __declspec(dllexport) int getInt(Test *self) {return self->getInt();}
    
    // Note: the '__declspec(dllexport)' is only necessary in Windows
}
Run Code Online (Sandbox Code Playgroud)

步骤2)编译DLL共享库。例如,从您的工作目录:

g++ -shared mytest.cpp -o libtest.dll

步骤 3)使用包装器创建 Python 文件:

#  mytest.py

import ctypes
import platform

# From Python 3.8 onwards, there is a reported bug in CDLL.__init__()
mode = dict(winmode=0) if platform.python_version() >= '3.8' else dict()  


lib = ctypes.CDLL('./libtest.dll', **mode)


class Test(object):
    def __init__(self, val: int):
        # Declare input and output types for each method you intend to use
        lib.init.argtypes = [ctypes.c_int]
        lib.init.restype = ctypes.c_void_p

        lib.setInt.argtypes = [ctypes.c_void_p, ctypes.c_int]
        lib.setInt.restype = ctypes.c_void_p

        lib.getInt.argtypes = [ctypes.c_void_p]
        lib.getInt.restype = ctypes.c_int

        self.obj = lib.init(val)

    def setInt(self, n):
        lib.setInt(self.obj, n)
    
    def getInt(self):
        return lib.getInt(self.obj)



T1 = Test(12)
print(T1.getInt())
T1.setInt(32)
print(T1.getInt())
Run Code Online (Sandbox Code Playgroud)

步骤 4) 运行代码

以下是我使用 4 个不同的 Python 版本运行脚本时的结果:

PS D:\Desktop\mytest> py -3.7 .\mytest.py
12
32
PS D:\Desktop\mytest> py -3.8 .\mytest.py
12
32
PS D:\Desktop\mytest> py -3.9 .\mytest.py
12
32
PS D:\Desktop\mytest> py -3.10 .\mytest.py
Traceback (most recent call last):
  File "D:\Desktop\mytest\mytest.py", line 7, in <module>
    lib = ctypes.CDLL('./libtest.dll', **mode)
  File "D:\Python\3102\lib\ctypes\__init__.py", line 374, in __init__
    self._handle = _dlopen(self._name, mode)
FileNotFoundError: Could not find module 'D:\Desktop\mytest\libtest.dll' (or one of its dependencies). Try using the full path with constructor syntax.
Run Code Online (Sandbox Code Playgroud)

在最后一种情况下,我尝试了完整路径,但仍然出现相同的错误。

我在 Windows 10 64 位上运行并使用 MinGW64 的 g++ 8.1.0 进行编译

评论:


bat*_*rat 6

我建议你尝试SWIG或sip(KDE/PyQt).

SWIG链接:http
://www.swig.org/ SIP链接:http://freshmeat.net/projects/python-sip/

这些可用于包装C++类并为它们提供Pythonic接口.