2016-10-29 2 views
1

Я нахожусь в Интернете в течение нескольких часов на этом этапе. Кто-нибудь знает, как разбирать namedtuple, возвращенный из функции python, в структуру или просто в отдельные переменные. Часть, с которой у меня возникают проблемы, - это получение данных из возвращаемого указателя. Я вызываю функцию python, встроенную в C++, используя вызов PyObject_CallFunction(), и я не знаю, что делать, если у меня есть PyObject * для возвращаемых данных.Python NamedTuple to C++ Struct

Я использую Python 2.7 для справки.

EDIT: В итоге я переместил всю функциональность, которую я пытался сделать как на Python, так и на C++, до Python. В ближайшее время я уточню о попытке стратегии, предложенной в комментариях к этому вопросу.

+0

Возможно, у вас возникли проблемы с преобразованием namedtuple, поскольку он не является встроенным. Попробуйте преобразовать namedtuple в кортеж сначала (с уровня python), затем используйте 'PyArg_ParseTuple' в вашем расширении C++. – thorhunter

+0

@thorhunter Я это сделаю. Я немного смутился, читая документацию PyArg_ParseTuple о том, как получить доступ к каждой части. Должен ли я точно знать, сколько байтов Python используется для хранения значений? – Wired365

+0

Нет, вам нужно знать только ту структуру кортежа, которую вы передаете, например. (int, int, string). Затем вы можете привязать их к типам C с помощью 'PyArg_ParseTuple (args," iis ", & int1, & int2, &str);' для 'int int1; int int2; char * str'. Это, конечно, основной пример, вы можете сделайте гораздо больше, используя 'PyArg_ParseTuple' и другие элементы API Python. Вы сможете извлечь любую информацию из PyObject, которая вам нужна (включая длину строки) с использованием Python API так или иначе. Я нашел эту ссылку довольно простой: https: //docs.python.org/2.0/ext/parseTuple.html – thorhunter

ответ

1

Я вызываю функцию питона, внедренный в C++ с помощью вызова PyObject_CallFunction(), и я не знаю, что делать, когда у меня есть PyObject * для возвращаемых данных.

A namedtuple является подклассом кортежей, который дополнительно предоставляет элементы кортежа в качестве названных атрибутов. Это означает, что вы можете выбрать, следует ли получать доступ к своим данным как obj[position] или obj.attribute. Последнее, как правило, более читаемо, но первое хорошо сочетается с распаковкой кортежа. В Python/C, вероятно, проще получить к нему доступ как кортеж, так как тогда вы можете использовать удобную функцию PyArg_ParseTuple, как указано в комментарии.

Чтобы извлечь произвольные атрибуты объекта (необязательно namedtuple), можно было бы позвонить PyObject_GetAttrString. Учитывая объект, описывающий, скажем, точку, извлекая атрибут такой, как x может выглядеть следующим образом:

PyObject *point = ...; // assume we get a new reference to point 
if (!point) 
    return NULL; 
PyObject *x = PyObject_GetAttrString(point, "x"); 
if (!x) { 
    // obj.x raised, possibly because point is of a different type 
    Py_DECREF(point); 
    return NULL; 
} 
double x_val = PyFloat_AsDouble(x); 
Py_DECREF(x);  // x not used below this line 
if (x_val == --1 && PyErr_Occurred()) { 
    // obj.x is not float or float-like 
    Py_DECREF(point); 
    return NULL; 
} 
Py_DECREF(point); // point not used below this line 

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

+0

Спасибо за альтернативный метод. Почему вы выполняете ту же проверку дважды в 'x_val && PyErr_Ocurred()' с тем, что похоже на то же содержимое в инструкции if? – Wired365

+0

@ Wired365 Просто скопируйте ошибку, извините. Код, который я изначально написал, также предназначен для извлечения 'y', но с проверкой ошибок и подсчетом referencex, это оказалось слишком длинным. Я отредактировал ответ, чтобы удалить дополнительную копию , а также изменил «throw ...», чтобы «вернуть NULL», поскольку это то, что вы обычно хотите сделать в Python/C. (Если вы планируете игнорировать ошибку и продолжать, не забудьте вызвать «PyErr_Clear» и, возможно, «PyErr_ExceptionMatches», чтобы убедиться, что вы игнорируете исключения, которые вы хотите игнорировать, а не все исключения там.) – user4815162342

+0

ahhh okay that's что я думал, что это может быть, но я просто хотел убедиться, что полностью понял тебя. Спасибо за разъяснения! – Wired365

0

namedtuple реализован исключительно на Python. Вы можете увидеть его полный источник в collection.py. Это очень коротко. Следует иметь в виду, что сама namedtuple - это функция, которая создает класс в кадре, в котором он вызывается, а затем возвращает этот класс (а не экземпляр этого класса). И именно этот возвращаемый класс используется для создания экземпляров. Таким образом, объект, который вы получаете, - это не то, что вы хотите передать на C++, если хотите передать отдельные экземпляры.

C++ создает struct определения во время компиляции. namedtuple создает классы namedtuple во время выполнения. Если вы хотите связать их с C++-структурами, используйте PyObject для создания экземпляров недавно измененного класса внутри C++ и назначьте их во время компиляции struct. Или создайте экземпляры нового чеканного класса в Python и передайте их на C++.

Или вы можете использовать метод _asdict (предоставляемый методом фабрики namedtuple для всех классов, которые он создает) и передать это на C++, чтобы затем привязать данные, определенные во время выполнения, к данным, заданным во время компиляции.

Если вы действительно хотите выполнить основную часть работы на C++, вы можете также использовать модуль Struct вместо использования namedtuple.

namedtuple - действительно швейцарский армейский нож Python для данных, который остается на Python. Он предоставляет позиционный доступ, именованный доступ, и все элементы также являются «свойствами» (поэтому у них есть метод доступа, который может использоваться в картах, фильтрах и т. Д. Вместо того, чтобы писать собственные lambdas).

Это место для таких вещей, как привязка БД (когда вы не знаете, какие столбцы будут там во время выполнения). Это менее clunky, чем OrderedDict для преобразования данных из одного формата в другой. Когда он используется таким образом, накладные расходы на обработку строк ничем не отличаются от фактического доступа к db (даже встроенного). Но я бы не использовал namedtuple для больших массивов структур, которые предназначены для использования в вычислениях.