SWIG в типографике работает, но аргумент не

У меня есть этот файл foobar.h

 class Foobar { public: void method(int arg[2]) {}; }; 

После компиляции интерфейса SWIG на Python, если я попытаюсь запустить этот метод с Python, он говорит:

 TypeError: in method 'Foobar_method', argument 2 of type 'int [2]' 

Безусловно. Поэтому я пишу эту картографическую карту SWIG:

 %typemap(in) int [2] {} 

и когда я скомпилирую это, Python запускает этот метод без жалоб. Поэтому я думаю, что я понимаю, как писать типовую карту.

Но, если я изменю типовую карту на argout :

 %typemap(argout) int [2] {} 

Теперь Python возвращается к предыдущей ошибке.

Я просто делаю это непосредственно из руководства SWIG, это должно работать без этой ошибки, как in типовой карте.

Что я делаю не так???

  • Преобразование std :: vector в массив NumPy без копирования данных
  • использование stdint с swig и numpy.i
  • Быстрое преобразование вектора C / C ++ в массив Numpy
  • Wrap C struct с элементом массива для доступа в python: SWIG? Cython? ctypes?
  • SWIG python инициализирует указатель на NULL
  • Python Properties & Swig
  • Как установить M2crypto в Windows
  • Динамическое связывание и Python SWIG (C ++) работает в C ++ сбой в python
  • One Solution collect form web for “SWIG в типографике работает, но аргумент не”

    Что не так?

    Короче говоря, это не одно или тоже предложение с этими типами.

    Ключевой бит информации, которую вы пропускаете, – это способ, которым несколько типов типов взаимодействуют, чтобы обернуть одну функцию.

    argout будет вставлен в сгенерированную оболочку после вызова. Это ваша возможность скопировать (теперь измененный) вход обратно на Python разумным способом.

    Это не затрагивает проблему того, как аргумент создается и передается перед вызовом.

    Вы можете увидеть это достаточно четко, проверив код, созданный этим интерфейсом:

     %module test %{ #include "test.h" %} %typemap(in) int[2] { // "In" typemap goes here } %typemap(argout) int[2] { // "argout" goes here } %include "test.h" 

    Который, когда test.h – ваш пример, производит:

      // ... <snip> arg1 = reinterpret_cast< Foobar * >(argp1); { // "In" typemap goes here } (arg1)->method(arg2); resultobj = SWIG_Py_Void(); { // "argout" goes here } return resultobj; // ... <snip> 

    В этих typemaps цель «in» typemap состоит в том, чтобы сделать arg2 разумной стоимостью перед вызовом, а карта «argout» должна делать что-то разумное со значениями после вызова (возможно, изменив возвращаемое значение, если вы хотите).


    Что должно быть в typemaps?

    Обычно для такой функции вы можете захотеть, чтобы карта ввода вводила временный массив из некоторых входов Python.

    Для этого нам нужно сначала изменить исходную типовую карту, попросив SWIG создать временный массив для нас:

    Важно, чтобы мы сделали SWIG для этого, используя обозначение добавления скобок после типа вместо того, чтобы добавлять его в тело типовой карты, чтобы область была верна для переменной. (Если бы мы не были временными, они не были бы доступны из карты «argout» еще и были бы очищены до того, как сам вызов был сделан).

     %typemap(in) int[2] (int temp[2]) { // If we defined the temporary here then it would be out of scope too early. // "In" typemap goes here } 

    Код, созданный SWIG, теперь включает в себя временный массив для нас, поэтому мы хотим использовать API Python C для итерации по нашему входу. Это может выглядеть примерно так:

     %typemap(in) int[2] (int temp[2]) { // "In" typemap goes here: for (Py_ssize_t i = 0; i < PyList_Size($input); ++i) { assert(i < sizeof temp/sizeof *temp); // Do something smarter temp[i] = PyInt_AsLong(PyList_GetItem($input, i)); // Handle errors } $1 = temp; // Use the temporary as our input } 

    (Мы бы предпочли использовать протокол итератора Python, если мы предпочли).

    Если мы скомпилируем и запустим интерфейс, то нам будет достаточно, чтобы передать вход, но ничего не возвращается. Прежде чем мы напишем «aboutout» typemap, в сгенерированном коде заметьте еще одну вещь. Наш временный массив в сгенерированном коде фактически выглядит как int temp2[2] . Это не ошибка. SWIG по умолчанию переименовал переменную, которая должна быть выведена из позиции аргумента, чтобы разрешить одну и ту же типовую карту применять несколько раз к одному вызову функции, если необходимо, по одному аргументу.

    В моей «аргументированной» типовой карте я собираюсь вернуть еще один список Python с новыми значениями. Это далеко не единственный разумный выбор, хотя есть другие варианты, если вы предпочитаете.

     %typemap(argout) int[2] { // "argout" goes here: PyObject *list = PyList_New(2); for (size_t i = 0; i < 2; ++i) { PyList_SetItem(list, i, PyInt_FromLong(temp$argnum[i])); } $result = list; } 

    В этой связи следует обратить внимание на то, что нам нужно написать temp$argnum явно, чтобы соответствовать преобразованию, которое SWIG сделал для нашего временного массива, и, во-вторых, мы используем $result в качестве результата.

    Чисто выходные аргументы

    Часто у нас есть аргумент, который используется только для вывода, а не для ввода. Для них нет смысла заставить пользователя Python предоставлять список, который просто игнорируется.

    Мы можем это сделать, изменив карту «in» typemap, используя numinputs=0 чтобы указать, что от Python не ожидается никакого ввода. Вы также должны позаботиться о том, чтобы инициализировать временное место здесь. Теперь типовая карта становится просто:

     %typemap(in,numinputs=0) int[2] (int temp[2]) { // "In" typemap goes here: memset(temp, 0, sizeof temp); $1 = temp; } 

    Так что теперь в «typemap» фактически не вводится какой-либо вход с Python. Его можно рассматривать как просто подготовку ввода к собственному вызову.

    В качестве альтернативы вы можете избежать обращения к имени, которое применяется SWIG (при том, что он не может использовать одну и ту же типовую карту несколько раз для одной и той же функции или с другой типовой страницей, которая имеет столкновение имен), используя noblock=1 в «в» типовой карте. Я бы не рекомендовал этого.

    Длина нефиксированного массива?

    Наконец, стоит отметить, что мы можем написать все эти typemaps, чтобы они были более универсальными и работали для любого фиксированного размера. Для этого мы заменяем 2 на «ЛЮБОЙ» в сопоставлении с картами, а затем используем $1_dim0 вместо 2 внутри тел типовой карты, поэтому весь интерфейс в конце этого становится:

     %module test %{ #include "test.h" %} %typemap(in,numinputs=0) int[ANY] (int temp[$1_dim0]) { // "In" typemap goes here: memset(temp, 0, sizeof temp); $1 = temp; } %typemap(argout) int[ANY] { // "argout" goes here: PyObject *list = PyList_New($1_dim0); for (size_t i = 0; i < $1_dim0; ++i) { PyList_SetItem(list, i, PyInt_FromLong(temp$argnum[i])); } $result = list; } %include "test.h" 
    Python - лучший язык программирования в мире.