I'm using SWIG to generate Python Bindings for my qt app. I have several places where I use QLists and I would like to integrate those QLists like std::vector from the SWIG Library (see http://www.swig.org/Doc1.3/Library.html#Library_nn15).
This means:
- The QList objects should be iterable from python (= they must be an iterable python object)
- It should be possible to pass a python list to a function which takes a qlist
- ... and all the other features listed in the SWIG Library for std::vector
To achieve that I use the following Code:
https://github.com/osmandapp/OsmAnd-core/blob/master/swig/java/QList.i
Later in my classes using QLists, I add code like:
%import "qlist.i"
%template(listfilter) QList<Interface_Filter*>;
class A {
public:
//.....
QList<Interface_Filter*> get_filters();
};
This works so far, but it doesn't give me the kind of integration I get with std::vector.
I'm having trouble finding out which parts of std_vector.i, std_container.i,... make an object iterable.
How do I need to extend the QList interface file to make my QList's iterable?
What you are asking for -- a qlist.i swig file that achieves the same level of integration for
QListin python as std_vector.i does forstd::vector-- is a non-trivial task.I provide a very basic extended qlist.i file (and qlisttest.i to show you how to use it) and will try to explain what steps are required.
qlist.i:qlisttest.i:Wrapping of
QListto make it and its methods accessible from pythonThis is achieved by making the (partial) class definition available to swig. That is what your current
qlist.idoes.Note: You might need to add a "template specialization" for the case
QList<T*>that typedefsconst_referenceasconst T*since you are using aQListof pointers. Otherwise,QList<T*>::const_referencewill beconst T*&, which apparently might confuse swig. (see swig/Lib/std/std_vector.i)Automatic conversion between python list and
QListThis is generally achieved by using swig typemaps. For instance, if you want a function
f(const QList<int>& list)to be able to accept a python list, you need to specify an input typemap that performs the conversion from a python list to aQList<int>:Here, the situation is more difficult in several ways:
QList: For this to work, you need to handle both cases in the typemap.Tto aQList<T>:This also involves a conversion for every element of the list from the wrapped type
Tto the plainT. This is achieved by the swig functionSWIG_ConvertPtr.%qlist_conversions(Type)that you can use to attach the typemap to theQList<Type>for a specificType.For the other conversion direction (
QList-> python list) you should first consider what you want. Consider a C++ function that returns aQList<int>. Calling this from python, should this return a wrappedQListobject, or should it automatically convert theQListto a python list?Accessing the wrapped
QListas a python sequence, i.e., makelenand[]work from pythonFor this, you need to extend the
QListclass in the qlist.i file using%extend { ... }and implement__len__and__getitem__methods.If slicing should also work, you need to provide a
__getitem__(PySliceObject *slice)__member method and input and "typecheck" typemaps forPySliceObjects.If you want to be able to modify values in the wrapped
QListusing[]from python, you need to implement__setitem__.For a list of all the useful methods you can implement to achieve better integration, see the python documentation on "builtin types" and "abstract base classes for containers".
Note: If you use the swig
-builtinfeature, then you need to additionally register the above functions to the appropriate "slots" using e.g.Making the wrapped
QListiterable from pythonFor this you need to extend the
QListclass and implement an__iter__()method that returns a python iterator object.A python iterator object is an object that provides the methods
__iter__()and__next__()(next()for older python), where__next__()returns the next value and raises the python exceptionStopIterationto signal the end.As mentioned before, you can implement the iterator object in python or C++. I show an example of doing this in python.
I hope this helps as a basis for you to tweak the functionality that you require.