【问题标题】:Python support for Qt dllPython 对 Qt dll 的支持
【发布时间】:2017-06-09 01:56:57
【问题描述】:

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

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

最好的方法是什么?

  • 用 Python 编写包装器,如果是的话,是否有障碍?
  • 不知道 PyQt 是否只是为了这个目的?
  • 或者您认为仅通过实现 C++ 库项目中使用的逻辑来重写 Python 中的 lib 是否更好。

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

Qt 的示例 API。

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

我想从 Python 调用这个函数。 函数参数CmdBaseSpv1ConnectionArgemitLogOptionLogInfo都是Qt类。 其中一些参数使用QOBJECT 基类。

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

【问题讨论】:

  • API 是什么样的?您需要在用户代码中使用 Qt 类吗?如果是,您是否还可以使用字符串和列表等 Python 原生类?
  • @GeorgSchölly 如果你指的是 QT API,它在很大程度上依赖于 QT 类和类型,例如 QString、quint32 等。
  • 你图书馆的 API 怎么样?您希望向 Python 公开的方法/类是什么样的?
  • 我已经编辑了问题并给出了一个示例 API。
  • 有点离题,但我会推荐 PySide 而不是 PyQt 来解决许可问题(PyQt 不超过 LGPL 版本)。

标签: python c++ qt pyqt wrapper


【解决方案1】:

我将写下我对包装 C++ 库的了解并尝试获取它,但作为巨大的免责声明,我自己仅将其用于非常非常简单的事情。

您询问有关用 Python 重写库的问题。我会说这取决于。如果代码是微不足道的,那么我不明白为什么不这样做。如果它更大并且必须与其他代码保持同步(正如您对.Net 所暗示的那样),我不会。为两者重用相同的代码是有意义的。

 我的建议

根据我对您的代码的了解,我会尝试使用 boost::pythonSWIG 包装它。

如何包装

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

如果您不需要任何 Qt 类来实例化您的类,这应该很简单。但是,如果您需要 Python 内部的 Qt 类型(例如,因为 CmdBaseSpv1 的构造函数需要 QString),您的任务会复杂得多,因为您需要一种将 Python 字符串转换为 @987654339 的方法@。如果可以的话,你应该只使用stl-types。

Python 中的一切

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

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

用手包裹

另一种方法是自己包装库调用。您可以使用Python API 来执行此操作。还有一些库可以帮助您创建绑定。 Boost::python 似乎特别有前途,并且可以与 C++ 一起使用。

绑定生成器

如果您的 API 非常大,您应该使用绑定生成器来解析 C++ 代码并自行生成绑定。例如sip 就是其中之一。它用于为整个 Qt 库创建绑定。那里有一些绑定生成器,Python 文档中提到的一个是SWIG。 PySide 使用Shiboken,并且在他们的网站上也有很好的描述。

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

PyQt

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

绑定的挑战

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

内存管理

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

def myfunc():
    mywidget = QWidget()

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

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

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

例外情况

并非所有编程语言都有异常或以相同的方式处理它们。例如,如果 C++ 中的异常可以在 Python 中捕获,那就太好了。

相关问题的链接

【讨论】:

  • 优秀的指导,谢谢。经过一整天的工作,我的发现; SWIG 不是为 Qt 设计的(我知道这有点可能但并不容易),SIP 很有希望,正在努力。对于 .Net 包装,我认为 Qt 内置了支持。即ActiveQt。我的工作可能会以 SIP 或为目标平台重写 SDK 结束。 SDK 的体积并不小,但幸运的是,它使用了遵循 Seperation Of Concerns 模式的隔离部分。因此不会引起太多的头痛。缺点将如您所述;更新所有平台的更改需要更多的工作。
  • @freewil:感谢您的更新。我希望您可以完全忽略绑定的整个 Qt 依赖性,并将对象视为常规 C++ 对象。不幸的是,祝你好运。
猜你喜欢
  • 2011-02-19
  • 1970-01-01
  • 2021-08-11
  • 2015-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多