2016-07-24 3 views
0

Согласно документам Swig и замечательному объяснению в SWIG in typemap works, but argout does not от @Flexo, карта-образ argout превращает ссылочные аргументы в возвращаемые значения в Python.Возвращаемые аргументы в SWIG/Python

У меня есть сценарий, в котором я передаю dict, который затем преобразуется в unordered_map в typemap(in), который затем заполняется в C++ lib. Поступая через код, я вижу, что отображение изменилось после того, как оно вернулось с C++, поэтому я задаюсь вопросом, почему нет возможности просто преобразовать unordered_map обратно на место в dict, который был передан. Или это возможно сейчас, и я просто что-то пропускаю?

Спасибо!

ответ

3

Я немного запутался, что именно вы просите, но мое понимание:

  • У вас есть «в» TypeMap для преобразования Python dict к C++ unordered_map для некоторой функции аргумента.
  • Затем функция изменяет unordered_map.
  • После завершения функции вы хотите, чтобы Python dict был обновлен до текущего unordered_map и каким-то образом возникли проблемы с этим шагом.
  • Поскольку вы знаете, как преобразовать dict к unordered_map, я предполагаю, что вы в принципе знаете, как преобразовать unordered_map обратно в dict с помощью Python C-API, но как-то не уверены, в какую SWIG TypeMap поместить код.

Таким образом, в этих предположениях, я постараюсь помочь:

  • "argout TypeMap превращает ссылочные аргументы в возвращаемые значения в Python". Не совсем, хотя он в основном используется для этой цели. "argout" typemap просто поставляет код для обработки некоторого аргумента функции (внутренне называемого $1), который вставляется в код оболочки после вызывается функция C++. Сравните это с «в» typemap, которая поставляет код для преобразования поставленного аргумента Python $input в аргумент C++ $1, который, очевидно, вставлен в код оболочки до, вызывается функция C++.

  • Оригинал передается на Python dict можно назвать в «argout» TypeMap, как $input, и модифицированный unordered_map как $1 (см SWIG документы связаны выше).

  • Следовательно, все, что вам нужно сделать, это написать «typout» typemap для той же сигнатуры аргумента, что и у «уже существующей» типовой карты, и вставить код (используя Python C-API) для обновления содержимое Python dict ($input), чтобы отразить содержимое unordered_map ($1).

  • Обратите внимание, что это отличается от классического использования «argout» typemaps, которые, как правило, преобразующих $1 обратно на новую Python dict и добавить это к возвратному объект Python, который вы можете обратиться к по $result.

Надеюсь, это поможет. Если вы все еще застряли в какой-то момент, отредактируйте свой вопрос, чтобы четко указать, в какой момент у вас возникли проблемы.

+0

Спасибо, много, m7thon! Вторая последняя пуля была темой, которую я отсутствовал. Из приведенных примеров Swig я думал, что ваша последняя пуля была единственным возможным способом передачи данных (с использованием возвращаемых значений). –

+1

@wr m7thon - это точка с этим ответом. Единственное, на что вы должны обратить внимание и сделать свой собственный ум, - это то, на что разработчик Python (т. Е. Пользователь ваших привязок) ожидает, что это будет поведение. В идеале вы хотите взять наименее запутанный маршрут. Для меня, как правило, в Python, чтобы сделать входные аргументы неизменяемыми, потому что в отличие от C++ вы не можете легко выводить (например) через const/not reference, каково будет поведение. Это в значительной степени оставляет возможность вернуть значение вместо этого в качестве опции, что часто имеет смысл, потому что return val не используется для указания успеха/неудачи в хорошо разработанных интерфейсах. – Flexo

0

Мне хорошо известно, что пользователь уже решил свою проблему, но здесь идет решение. Некоторая проверка входных данных может быть введена, чтобы избежать нестроковых значений входного словаря.

Заголовочный файл

// File: test.h 
#pragma once 

#include <iostream> 
#include <string> 
#include <unordered_map> 

void method(std::unordered_map<std::string, std::string>* inout) { 

    for(const auto& n : (*inout)) { 
    std::cout << "Key:[" << n.first << "] Value:[" << n.second << "]\n"; 
    } 

    (*inout)["BLACK"] = "#000000"; 
}; 

файл интерфейса

// File : dictmap.i 
%module dictmap 

%{ 
    #include "test.h" 
%} 

%include "typemaps.i" 

%typemap(in) std::unordered_map<std::string, std::string>* (std::unordered_map<std::string, std::string> temp) { 

    PyObject *key, *value; 
    Py_ssize_t pos = 0; 

    $1 = &temp; 

    temp = std::unordered_map<std::string, std::string>(); 
    while (PyDict_Next($input, &pos, &key, &value)) { 
    (*$1)[PyString_AsString(key)] = std::string(PyString_AsString(value)); 
    } 
} 

%typemap(argout) std::unordered_map<std::string, std::string>* { 
$result = PyDict_New(); 
for(const auto& n : *$1) { 
    PyDict_SetItemString($result, n.first.c_str(), 
      PyString_FromString(n.second.c_str())); 
} 
} 
%include "test.h" 

Тест

import dictmap 
out = dictmap.method({'WHITE' : '#FFFFFF'}) 

Выход обновленный словарь

In[2]: out 
Out[3] : {'BLACK': '#000000', 'WHITE': '#FFFFFF'} 
+0

Обратите внимание, что при работе с python3 вы можете обнаружить, что 'PyString_AsString' продолжает возвращать нулевой указатель. Возможно, вам придется использовать 'PyUnicode_AsUTF8' вместо' PyString_AsString'. –

Смежные вопросы