Python 支持 Qt dll

Python support for Qt dll

我有自己的用 Qt 编写的 C++ 库项目(带源代码),它使用 QTcpsocketQUdpSocketQSerialPort 信号和槽。

我也想在 Python 中支持这个库。

执行此操作的首选方法是什么?

因为这个库是 SDK 的一部分,所以同样适用于使用 .NET 支持 QT dll 实际上,作为支持 Python 后的第二步。

Qt 的示例 API。

quint16 SendCommandAsync(CmdBaseSpv1* pcommand,
                         ConnectionArg connectionArg,
                         emitLogOptions::emitLogOption logOption,
                         LogInfo &txLogInfo,
                         LogInfo &rxLogInfo);

我想从 Python 调用这个函数。 函数参数CmdBaseSpv1ConnectionArgemitLogOptionLogInfo都是Qt的classes。 其中一些参数使用 QOBJECT 基础 class.

从函数名可以看出;它是一个异步函数调用。结果将发出一个信号,所以我也需要获得异步结果。

我会写下我所知道的关于包装 C++ 库的知识,并尝试获取它的源代码,但作为一个巨大的免责声明,我只将它用于非常非常非常重要的事情简单我自己。

您询问重写 Python 中的库。我会说这取决于。如果代码很简单,那么我不明白为什么不这样做。如果它更大并且必须与其他代码一起保持 up-to-date(正如您暗示的那样。Net),我不会。为两者重用相同的代码是有意义的。

我的建议

根据我对您代码的了解,我会尝试使用 boost::python or SWIG.

对其进行包装

如何包装

主要的麻烦是在 Python 中创建 CmdBaseSpv1ConnectionArg 等。

如果您不需要任何 Qt-classes 来实例化您的 类,这应该很简单。但是,如果您需要 Python 中的 Qt 类型(例如,因为 CmdBaseSpv1 的构造函数需要 QString),您的任务要复杂得多,因为您需要一种方法来转换一个Python-string变成了一个QString。如果可以,您应该只使用 stl 类型。

Python

中的所有内容

包装小型 C 库的最简单方法是使用 cffi module (or ctypes)。您可以在 Python 中编写完整的绑定。但是,如果您的 API 很大并且会变得困难,那么这需要大量的手动工作。

还有一个问题:ctypes是only compatible with C,不是C++。所以你需要改变你的界面以与 C 兼容,在内部你仍然可以使用 C++ 和 Qt。

手工包裹

另一种方法是自己包装库调用。您可以通过使用 Python API. There are also a few libraries that help you create the bindings. Boost::python 来做到这一点似乎特别有前途并且可以与 C++ 一起使用。

绑定生成器

如果您的 API 非常大,您应该使用绑定生成器来解析 C++ 代码并自行生成绑定。例如 sip is one of them. It is used to create the bindings for the whole Qt library. There are a few binding generators out there, one mentioned in the Python docs is SWIG. PySide uses Shiboken 并且在他们的网站上也有很好的描述。

SWIG 具有额外的优势,您可以为多种语言创建绑定,包括 C#。

PyQt

PyQt 是使用 sip 从 Qt 生成的绑定。您可能不需要它,除非您需要从 Python 内部访问 Qt 的全部功能。如果是这种情况,请考虑使用 sip 来生成绑定,这样 signal-slot 机制就可以在您的库和 PyQt 之间兼容。

绑定方面的挑战

绑定带来了一些挑战,因为 Python 和 C++ 在一些关键领域是不同的。

Memory-management

Python 中的内存管理几乎是自动的,在 C++ 中,您需要手动执行。例如

def myfunc():
    mywidget = QWidget()

myfunc() 结束时,mywidget 被垃圾收集。然而在 C++ 中

void myfunc() {
    auto mywidget = new QWidget();
}

mywidget 还在。这意味着即使在 Python 内部,您也需要注意 C++ 内存管理。我见过的问题是内存泄漏和悬挂指针。使用回调时要注意这一点,您不希望 Python 在 C++ 认为它仍然存在时对回调进行垃圾收集。

例外情况

并非所有的编程语言都有异常或以相同的方式处理它们。例如,如果可以在 Python.

中捕获 C++ 中的异常,那就太好了

相关问题的链接

  • How to wrap a c++ library for python?(boost::python 的例子)
  • Exposing a C++ API to Python(关于 boost::python、SWIG 等的讨论)
  • (讨论 Cython,另一种选择)