如果您希望能够使用 python 中的 [] 修改包装的 QList 中的值,则需要实现 __setitem__.有关您可以实现以实现更好集成的所有有用方法的列表,请参阅有关内置类型"和容器的抽象基类"的 Python 文档.注意:如果您使用 swig -builtin 功能,那么您需要使用例如额外将上述功能注册到适当的插槽"%feature("python:slot", "sq_length", functype="lenfunc") __len__;使包装的 QList 可从 python 迭代为此,您需要扩展 QList 类并实现返回 Python 迭代器对象的 __iter__() 方法.python 迭代器对象是一个提供方法 __iter__() 和 __next__() (next() 用于较旧的python)的对象,其中 __next__() 返回下一个值并引发 python 异常 StopIteration 以表示结束.如前所述,您可以在python或C++中实现迭代器对象.我展示了一个在 python 中执行此操作的示例.我希望这有助于作为您调整所需功能的基础.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::vectorTo achieve that I use the following Code:https://github.com/osmandapp/OsmAnd-core/blob/master/swig/java/QList.iLater 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 QList in python as std_vector.i does for std::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:%{#include <QList>%}%pythoncode %{class QListIterator: def __init__(self, qlist): self.index = 0 self.qlist = qlist def __iter__(self): return self def next(self): if self.index >= self.qlist.size(): raise StopIteration; ret = self.qlist.get(self.index) self.index += 1 return ret __next__ = next%}template<class T> class QList {public:class iterator;typedef size_t size_type;typedef T value_type;typedef const value_type& const_reference;QList();size_type size() const;void reserve(size_type n);%rename(isEmpty) empty;bool empty() const;void clear();%rename(add) push_back;void push_back(const value_type& x);%extend { const_reference get(int i) throw (std::out_of_range) { int size = int(self->size()); if (i>=0 && i<size) return (*self)[i]; else throw std::out_of_range("QList index out of range"); } void set(int i, const value_type& val) throw (std::out_of_range) { int size = int(self->size()); if (i>=0 && i<size) (*self)[i] = val; else throw std::out_of_range("QList index out of range"); } int __len__() { return self->size(); } const_reference __getitem__(int i) throw (std::out_of_range) { int size = int(self->size()); if (i>=0 && i<size) return (*self)[i]; else throw std::out_of_range("QList index out of range"); } %pythoncode %{ def __iter__(self): return QListIterator(self) %}}};%define %qlist_conversions(Type...)%typemap(in) const QList< Type > & (bool free_qlist){free_qlist = false;if ((SWIG_ConvertPtr($input, (void **) &$1, $1_descriptor, 0)) == -1) { if (!PyList_Check($input)) { PyErr_Format(PyExc_TypeError, "QList or python list required."); SWIG_fail; } Py_ssize_t len = PyList_Size($input); QList< Type > * qlist = new QList< Type >(); free_qlist = true; qlist->reserve(len); for (Py_ssize_t index = 0; index < len; ++index) { PyObject *item = PyList_GetItem($input,index); Type* c_item; if ((SWIG_ConvertPtr(item, (void **) &c_item, $descriptor(Type *),0)) == -1) { delete qlist; free_qlist = false; PyErr_Format(PyExc_TypeError, "List element of wrong type encountered."); SWIG_fail; } qlist->append(*c_item); } $1 = qlist;}}%typemap(freearg) const QList< Type > &{ if (free_qlist$argnum and $1) delete $1; }%enddefqlisttest.i:%module qlist;%include "qlist.i"%inline %{class Foo {public: int foo;};%}%template(QList_Foo) QList<Foo>;%qlist_conversions(Foo);%inline %{int sumList(const QList<Foo> & list) { int sum = 0; for (int i = 0; i < list.size(); ++i) { sum += list[i].foo; } return sum;}%}Wrapping of QList to 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.i does.Note: You might need to add a "template specialization" for the case QList<T*> that typedefs const_reference as const T* since you are using a QList of pointers. Otherwise, QList<T*>::const_reference will be const 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 a QList<int>:%typemap(in) const QList<int> &{ PyObject * py_list = $input; [check if py_list is really a python list of integers] QList<int>* qlist = new QList<int>(); [copy the data from the py_list to the qlist] $1 = qlist;}%typemap(freearg) const QList<int> &{ if ($1) delete $1; }Here, the situation is more difficult in several ways:You want to be able to pass a python lists or a wrapped QList: For this to work, you need to handle both cases in the typemap.You want to convert a python list of wrapped type T to a QList<T>:This also involves a conversion for every element of the list from the wrapped type T to the plain T. This is achieved by the swig function SWIG_ConvertPtr.I am not sure if you can specify typemaps with template arguments. Therefore, I wrote a swig macro %qlist_conversions(Type) that you can use to attach the typemap to the QList<Type> for a specific Type.For the other conversion direction (QList -> python list) you should first consider what you want. Consider a C++ function that returns a QList<int>. Calling this from python, should this return a wrapped QList object, or should it automatically convert the QList to a python list?Accessing the wrapped QList as a python sequence, i.e., make len and [] work from pythonFor this, you need to extend the QList class 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 for PySliceObjects.If you want to be able to modify values in the wrapped QList using [] 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 -builtin feature, then you need to additionally register the above functions to the appropriate "slots" using e.g.%feature("python:slot", "sq_length", functype="lenfunc") __len__;Making the wrapped QList iterable from pythonFor this you need to extend the QList class 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 exception StopIteration to 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. 这篇关于swig:如何制作 QList&lt;T&gt;可迭代,如 std::vector的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
06-28 23:22