Массив передачи структур от Python до C

[Обновление: проблема решена! Посмотрите нижнюю часть сообщения]

Я должен позволить разработчикам Python передавать массив упакованных данных (в этом случае вершины) в мой API, который является серией интерфейсов C++, представленных вручную через API Python C. Мое начальное впечатление с этим должно использовать ctypes класс Структуры для обеспечения интерфейса как это:

class Vertex(Structure):
_fields_ = [
    ('x', c_float),
    ('y', c_float),
    ('z', c_float),
    ('u', c_float),
    ('v', c_float),
    ('color', c_int)
] 

verts = (Vertex * 3)()
verts[0] = Vertex(0.0, 0.5, 0.0, 0.0, 0.5, 0xFF0000FF)
verts[1] = Vertex(0.5, -0.5, 0.0, 0.5, -0.5, 0x00FF00FF)
verts[2] = Vertex(-0.5, -0.5, 0.0, -0.5, -0.5, 0x0000FFFF)

device.ReadVertices(verts, 3) # This is the interfaces to the C++ object

Где функция, которой я пытаюсь передать, имеет следующую подпись:

void Device::ReadVertices(Vertex* verts, int count);

И обертка Python выглядит примерно так:

static PyObject* Device_ReadVertices(Py_Device* self, PyObject* args)
{
    PyObject* py_verts;
    int count;

    if(!PyArg_ParseTuple(args, "Oi", &py_verts, &count)) 
        return NULL;

    // This Doesn't Work!
    Vertex* verts = static_cast<Vertex*>(PyCObject_AsVoidPtr(py_verts));

    self->device->ReadVertices(verts, count);

    Py_RETURN_NONE;
}

Конечно, самая большая проблема, которую я имею, является этим: Я могу получить PyObject для структуры, но я понятия не имею, как я бросил бы его к корректному типу. Вышеупомянутый код терпит полный провал. Таким образом, как точно я пошел бы о разрешении пользователю передать меня этот вид данных из Python?

Теперь, несколько вещей рассмотреть: Сначала то, что у меня уже есть довольно мало своего записанного слоя Python/C++, и совершенно довольно им (я переехал от БОЛЬШОГО ГЛОТКА, таким образом, у меня могло быть больше гибкости). Я не хочу повторно кодировать его, таким образом, я предпочел бы решение, которое работает с API C исходно. Во-вторых, я действительно намереваюсь иметь структуру Вершины, предопределены в моем коде C++, таким образом, я предпочел бы не сделать пользователя, должен переопределить его в Python (сокращает ошибки тот путь), но я не уверен, как представить непрерывную структуру как этот. В-третьих, у меня нет причины попытки ctypes структуры кроме не знания другого способа сделать это. Любые предложения приветствуются. Наконец, так как это (как Вы, возможно, предположили) для графического приложения, я предпочел бы более быстрый метод по удобному, даже если более быстрый метод берет немного больше работы.

Спасибо за любую справку! Я все еще чувствую свой путь вокруг расширений Python, таким образом, это - большая справка для получения общественного входа на некоторых более липких частях.

[РЕШЕНИЕ]

Так прежде всего, благодаря всем, кто сделал подачу в их идеях. Это было много небольших лакомых кусочков, которые составили в целом возможный ответ. В конце вот то, что я нашел: предложение Sam использования struct.pack закончило тем, что было правильным на деньгах. Видение, что я использую Python 3, я должен был настроить его очень немного, но когда все было сказано, и сделанный это на самом деле разбудило показ треугольника на моем экране:

verts = bytes()
verts += struct.pack("fffffI", 0.0, 0.5, 0.0, 0.0, 0.5, 0xFF0000FF)
verts += struct.pack("fffffI", 0.5, -0.5, 0.0, 0.5, -0.5, 0x00FF00FF)
verts += struct.pack("fffffI", -0.5, -0.5, 0.0, -0.5, -0.5, 0x0000FFFF)

device.ReadVertices(verts, 3)

С моим кортежем, анализирующим теперь бывший похожий на это:

static PyObject* Device_ReadVertices(Py_Device* self, PyObject* args)
{
    void* py_verts;
    int len, count;

    if(!PyArg_ParseTuple(args, "y#i", &py_verts, &len, &count)) 
        return NULL;

    // Works now!
    Vertex* verts = static_cast<Vertex*>(py_verts);

    self->device->ReadVertices(verts, count);

    Py_RETURN_NONE;
}

Обратите внимание на это даже при том, что я не использую len переменная в этом примере (хотя я буду в конечном продукте) я должен проанализировать кортеж с помощью 'y#' вместо просто 'y', или иначе это остановится в первом ПУСТОМ УКАЗАТЕЛЕ (согласно документации). Также быть рассмотренным: освободите*, броски как это довольно опасны, поэтому сделайте загрузки больше проверки ошибок, чем я показываю здесь!

Так, задание хорошо сделанный, счастливый день, соберитесь и пойдите домой, да?

Ожидайте!Не так быстро! Существует БОЛЬШЕ!

Чувствование себя хорошо о том, как это все решило, что я решил на прихоти, видеть, аварийно завершилась ли моя предыдущая попытка все еще на мне и вернулась назад к первому отрывку Python в этом сообщении. (Использование нового кода C, конечно), и... это работало! Результаты были идентичны struct.pack версии! Ничего себе!

Таким образом, это означает, что у Ваших пользователей есть выбор в том, как они собираются обеспечить этот вид данных, и Ваш код может обработать любого без изменений. Лично я собираюсь поощрить ctype. Метод структуры, так как я думаю, что он делает для более легкой удобочитаемости, но действительно это - то, чем пользователь доволен. (Heck, они могли вручную вывести строку байтов в шестнадцатеричном числе, если бы они хотели. Это работает. Я попробовал.)

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

9
задан Toji 21 February 2010 в 18:53
поделиться

2 ответа

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

На стороне Python упакуйте вершины в строку вместо объекта.

str = "" # byte stream for encoding data
str += struct.pack("5f i", vert1.x, vert1.y, vert1.z, vert1.u, vert1.v, vert1.color) # 5 floats and an int
# same for other vertices

device. ReadVertices( verts, 3) # send vertices to C library

В библиотеке C / оболочке Python измените PyArgs_ParseTuple, чтобы использовать строку формата «si» . Это преобразует вашу строку python в строку C (char *), которую вы затем можете преобразовать как указатель на вашу векторную структуру. На данный момент строка C представляет собой поток байтов / слов / чисел с плавающей запятой и должна быть тем, что вы ищете.

Удачи!

2
ответ дан 3 November 2019 в 08:20
поделиться

Самое простое, что я могу сделать, - это просто полностью избежать проблемы и предоставить Device_ReadVertex, который принимает в качестве аргументов x, y, z, u, v и цвет. Это имеет очевидные недостатки, например, заставляет программистов Python скармливать ему вершины одну за другой.

Если этого недостаточно (кажется, что это не так), вы можете попробовать определить новый тип Python, как описано здесь . Это немного больше кода, но я думаю, что это более «архитектурно обоснованный» метод, потому что вы гарантируете, что ваши разработчики Python используют такое же определение типа, как и вы в коде C. Он также обеспечивает немного большую гибкость, чем простая структура (на самом деле это класс с возможностью добавления методов и т. Д.), Что, я не уверен, вам действительно нужно, но может пригодиться позже.

1
ответ дан 3 November 2019 в 08:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: