Python 支持 Qt dll
Python support for Qt dll
我有自己的用 Qt 编写的 C++ 库项目(带源代码),它使用 QTcpsocket
、QUdpSocket
、QSerialPort
信号和槽。
我也想在 Python 中支持这个库。
执行此操作的首选方法是什么?
- 在Python中写一个包装器,如果是这样有障碍吗?
- 不知道 PyQt 是不是就是为了这个目的?
- 或者您认为通过仅实现 C++ 库项目中使用的逻辑来重写 Python 中的库是否更好。
因为这个库是 SDK 的一部分,所以同样适用于使用 .NET 支持 QT dll 实际上,作为支持 Python 后的第二步。
Qt 的示例 API。
quint16 SendCommandAsync(CmdBaseSpv1* pcommand,
ConnectionArg connectionArg,
emitLogOptions::emitLogOption logOption,
LogInfo &txLogInfo,
LogInfo &rxLogInfo);
我想从 Python 调用这个函数。
函数参数CmdBaseSpv1
、ConnectionArg
、emitLogOption
、LogInfo
都是Qt的classes。
其中一些参数使用 QOBJECT
基础 class.
从函数名可以看出;它是一个异步函数调用。结果将发出一个信号,所以我也需要获得异步结果。
我会写下我所知道的关于包装 C++ 库的知识,并尝试获取它的源代码,但作为一个巨大的免责声明,我只将它用于非常非常非常重要的事情简单我自己。
您询问重写 Python 中的库。我会说这取决于。如果代码很简单,那么我不明白为什么不这样做。如果它更大并且必须与其他代码一起保持 up-to-date(正如您暗示的那样。Net),我不会。为两者重用相同的代码是有意义的。
我的建议
根据我对您代码的了解,我会尝试使用 boost::python or SWIG.
对其进行包装
如何包装
主要的麻烦是在 Python 中创建 CmdBaseSpv1
、ConnectionArg
等。
如果您不需要任何 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,另一种选择)
我有自己的用 Qt 编写的 C++ 库项目(带源代码),它使用 QTcpsocket
、QUdpSocket
、QSerialPort
信号和槽。
我也想在 Python 中支持这个库。
执行此操作的首选方法是什么?
- 在Python中写一个包装器,如果是这样有障碍吗?
- 不知道 PyQt 是不是就是为了这个目的?
- 或者您认为通过仅实现 C++ 库项目中使用的逻辑来重写 Python 中的库是否更好。
因为这个库是 SDK 的一部分,所以同样适用于使用 .NET 支持 QT dll 实际上,作为支持 Python 后的第二步。
Qt 的示例 API。
quint16 SendCommandAsync(CmdBaseSpv1* pcommand,
ConnectionArg connectionArg,
emitLogOptions::emitLogOption logOption,
LogInfo &txLogInfo,
LogInfo &rxLogInfo);
我想从 Python 调用这个函数。
函数参数CmdBaseSpv1
、ConnectionArg
、emitLogOption
、LogInfo
都是Qt的classes。
其中一些参数使用 QOBJECT
基础 class.
从函数名可以看出;它是一个异步函数调用。结果将发出一个信号,所以我也需要获得异步结果。
我会写下我所知道的关于包装 C++ 库的知识,并尝试获取它的源代码,但作为一个巨大的免责声明,我只将它用于非常非常非常重要的事情简单我自己。
您询问重写 Python 中的库。我会说这取决于。如果代码很简单,那么我不明白为什么不这样做。如果它更大并且必须与其他代码一起保持 up-to-date(正如您暗示的那样。Net),我不会。为两者重用相同的代码是有意义的。
我的建议
根据我对您代码的了解,我会尝试使用 boost::python or SWIG.
对其进行包装如何包装
主要的麻烦是在 Python 中创建 CmdBaseSpv1
、ConnectionArg
等。
如果您不需要任何 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,另一种选择)