Search code examples
pythonc++swig

How can I correctly create a C++ vector in Python3 by swig?


I try to test swig library 'std_vector.i', but I can't create a vector in Python3 like official demo, Here is some information.

swig_test.i

%module swig_test

%{
#include <vector>
void worker(std::vector<int> &v) {
    v.push_back(123);
}
%}

%include <std_vector.i>
%template(MyVector) std::vector<int>;

void worker(std::vector<int> &v);

Then I run:

swig -python -py3 -c++ swig_test.i

It works right. And then is setup.py

from distutils.core import setup, Extension

test_module = Extension('_swig_test',
                           sources=['swig_test_wrap.cxx'],
                           )

setup(name = 'swig_test',
       version = '0.1',
       author      = "SWIG Docs",
       description = """Simple swig test from docs""",
       ext_modules = [test_module],
       py_modules = ["swig_test"],)

And then run:

python setup.py build_ext --inplace

It creates the file '_swig_test.cp38-win_amd64.pyd', I test it in the shell.

>>> import _swig_test
>>> v = _swig_test.MyVector([1,2,3])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module '_swig_test' has no attribute 'MyVector'

It's too strange, it can't be work as normal, then I run dir

>>> dir(_swig_test)
['MyVector___bool__', 'MyVector___delitem__', 'MyVector___delslice__', 'MyVector___getitem__', 'MyVector___getslice__', 'MyVector___len__', 'MyVector___nonzero__', 'MyVector___setitem__', 'MyVector___setslice__', 'MyVector_append', 'MyVector_assign', 'MyVector_back', 'MyVector_begin', 'MyVector_capacity', 'MyVector_clear', 'MyVector_empty', 'MyVector_end', 'MyVector_erase', 'MyVector_front', 'MyVector_get_allocator', 'MyVector_insert', 'MyVector_iterator', 'MyVector_pop', 'MyVector_pop_back', 'MyVector_push_back', 'MyVector_rbegin', 'MyVector_rend', 'MyVector_reserve', 'MyVector_resize', 'MyVector_size', 'MyVector_swap', 'MyVector_swiginit', 'MyVector_swigregister', 'SWIG_PyInstanceMethod_New', 'SwigPyIterator___add__', 'SwigPyIterator___eq__', 'SwigPyIterator___iadd__', 'SwigPyIterator___isub__', 'SwigPyIterator___ne__', 'SwigPyIterator___next__', 'SwigPyIterator___sub__', 'SwigPyIterator_advance', 'SwigPyIterator_copy', 'SwigPyIterator_decr', 'SwigPyIterator_distance', 'SwigPyIterator_equal', 'SwigPyIterator_incr', 'SwigPyIterator_next', 'SwigPyIterator_previous', 'SwigPyIterator_swigregister', 'SwigPyIterator_value', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'delete_MyVector', 'delete_SwigPyIterator', 'new_MyVector', 'worker']

I try to add #define SWIG_FILE_WITH_INIT, but it have no any use, and I try to imitate official demo, it works same result.

How can I deal with it?


Solution

  • The problem here is how you're importing and using the module you've built.

    When you ran SWIG as well as generating some C++ code it also generated some Python too. Rather than directly access the native module you want to access it via the generated python instead, e.g.

    import swig_test # Note no leading _
    v = swig_test.MyVector([1,2,3])
    

    Which will work just fine then.

    Note that you can also ask SWIG to generate native-only module by invoking SWIG with the -builtin flag as well, e.g.:

    swig -python -py3 -c++ -builtin swig_test.i
    

    However I wouldn't usually recommend this when getting started as it makes a bunch of common things quite a lot harder.