Python support for Qt dll

雨燕双飞 提交于 2019-12-11 07:34:45

问题


I have my own C++ library project(with source) written in Qt and it uses QTcpsocket, QUdpSocket, QSerialPort signals and slots.

I would like to support this library in Python as well.

What is the preferred way to do this?

  • Writing a wrapper in Python, if so does it have obstacles?
  • Dont know if PyQt is just for this purpose?
  • Or do you thnink is it better to rewrite the lib in Python by just implementing the logic used in C++ library project.

As this is library is part of a SDK, same applies for supporting QT dll with .NET as well in fact, as a second step after supporting Python.

Example API of Qt.

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

I want to call this function from Python. Function parameters CmdBaseSpv1, ConnectionArg, emitLogOption, LogInfo are all Qt classes. Some of these arguments are using the QOBJECT base class.

As you see from the function name; it is an Asynchronous function call. Result will emit a signal so I need to get async result as well.


回答1:


I'll write down what I know about wrapping C++ libraries and will try to source it, but as a huge disclaimer, I have only used this for something very, very simple myself.

You ask about rewriting the library in Python. I would say this depends. If the code is trivial, then I don't see why not. If it is larger and has to be kept up-to-date with other code (as you imply with .Net), I wouldn't. It makes sense to reuse the same code for both.

 My suggestion

From what I see of your code I would try to wrap it using boost::python or SWIG.

How to wrap

The main trouble is going to be to create CmdBaseSpv1, ConnectionArg, etc. in Python.

If you don't need any Qt-classes to instantiate your classes, this should be straightforward. However, in case you need the Qt types inside of Python (e.g. because the constructor of CmdBaseSpv1 requires a QString), your task is a lot more complicated because you need a way to convert a Python-string into a QString. If you can, you should only use stl-types.

Everything in Python

The simplest way to wrap a small C library is to use the cffi module (or ctypes). You can write the full binding in Python. However, this is a lot of manual work if your API is large and can get difficult.

There is another problem: ctypes is only compatible with C, not C++. So you'd need to change your interface to be compatible with C, internally you could still use C++ and Qt.

Wrap by hand

An alternative is to wrap the library calls yourself. You can either do this by using the Python API. There are also a few libraries that help you create the bindings. Boost::python seems especially promising and works with C++.

Binding generators

If your API is very large, you should use a binding generator which parses the C++ code and generates the bindings itself. For example 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 and also has a nice description of it on their website.

SWIG has the additional advantage, that you can create bindings for multiple languages, including C#.

PyQt

PyQt is a binding generated from Qt using sip. You'll probably not need it, unless you need to access the full power of Qt from inside Python. If this is the case, consider using sipfor generating the bindings, so things like the signal-slot mechanism are compatible between your library and PyQt.

Challenges with bindings

Bindings come with a few challenges because Python and C++ are different in some key areas.

Memory-management

Memory management in Python is almost automatic, in C++ you're required to do it manually. For example

def myfunc():
    mywidget = QWidget()

at the end of myfunc() mywidget gets garbage collected. In C++ however

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

mywidget is still around. This means that even when inside Python, you need to take care of the C++ memory management. The problems I've seen are memory leaks and dangling pointers. Watch out for this when using callbacks, you don't want Python to garbage collect the callback while C++ thinks it's still alive.

Exceptions

Not all programming languages have exceptions or deal with them the same way. For example, it would be nice if an exception inside C++ can be caught inside Python.

Links to related question

  • How to wrap a c++ library for python? (example of boost::python)
  • Exposing a C++ API to Python (discussion about boost::python, SWIG and more)
  • https://stackoverflow.com/a/5686873 (discusses Cython, another choice)


来源:https://stackoverflow.com/questions/41825296/python-support-for-qt-dll

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!