Übergeben Sie ein Array von Strukturen von Python an C

9

[Update: Problem gelöst! Siehe unten im Beitrag]

Ich muss Python-Entwicklern erlauben, ein Array gepackter Daten (in diesem Fall Scheitelpunkte) in meine API zu übergeben, die eine Reihe von C ++ - Interfaces darstellt, die manuell über die Python-C-API verfügbar gemacht werden. Mein erster Eindruck dabei ist, die ctypes-Struktur-Klasse zu verwenden, um eine Schnittstelle wie folgt zu ermöglichen:

%Vor%

Wo die Funktion, an die ich zu senden versuche, die folgende Signatur hat:

%Vor%

Und der Python-Wrapper sieht ungefähr so ​​aus:

%Vor%

Natürlich ist das größte Problem, das ich habe, das: Ich kann das PyObject für die Struktur abrufen, aber ich habe keine Ahnung, wie ich es auf den richtigen Typ umwandeln würde. Der obige Code versagt kläglich. Also, wie genau würde ich dem Benutzer erlauben, mir diese Art von Daten von Python zu übergeben?

Nun ein paar Dinge zu beachten: Erstens, dass ich schon ziemlich viel von meiner Python / C ++ - Ebene geschrieben habe, und ich bin vollkommen zufrieden damit (ich entfernte mich von SWIG, um mehr Flexibilität zu haben). Ich möchte es nicht neu codieren, daher würde ich eine Lösung bevorzugen, die nativ mit der C-API arbeitet. Zweitens beabsichtige ich, die Vertex-Struktur in meinem C ++ - Code vordefiniert zu haben, also würde ich es vorziehen, wenn der Benutzer es nicht in Python neu definieren müsste (reduziert Fehler auf diese Weise), aber ich bin es Ich bin mir nicht sicher, wie man eine zusammenhängende Struktur so aussetzen kann. Drittens habe ich keinen Grund, die Ctypes-Struktur zu versuchen, abgesehen davon, dass ich keinen anderen Weg kenne, dies zu tun. Irgendwelche Vorschläge sind willkommen. Schließlich, da dies für eine Grafik-App der Fall ist, würde ich eine schnellere Methode bevorzugen, selbst wenn die schnellere Methode ein bisschen mehr Arbeit erfordert.

Danke für jede Hilfe! Ich fühle mich immer noch in der Nähe von Python-Erweiterungen, so dass es eine große Hilfe ist, Community-Input für einige der klebrigeren Teile zu bekommen.

[LÖSUNG]

Also erstmal, danke an alle, die ihre Ideen eingebracht haben. Es waren eine Menge kleiner Leckerbissen, die zur letzten Antwort beitrugen. Am Ende ist das, was ich gefunden habe: Sams Vorschlag, struct.pack zu verwenden, endete damit, dass er direkt am Geld saß. Als ich sah, dass ich Python 3 benutze, musste ich es ein wenig verändern, aber als alles gesagt und getan war, bekam ich tatsächlich ein Dreieck auf meinem Bildschirm:

%Vor%

Wenn mein Tupel-Parsing jetzt so aussieht:

%Vor%

Beachten Sie, dass ich, obwohl ich die Variable len in diesem Beispiel nicht verwende (obwohl ich im Endprodukt bin), das Tupel mit 'y #' statt nur 'y' analysieren muss, sonst wird es das tun Stoppe beim ersten NULL (laut Dokumentation). Auch zu beachten: void * casts wie diese sind ziemlich gefährlich, also bitte viel mehr Fehlerüberprüfung als ich hier zeige!

Also, Arbeit gut gemacht, glücklicher Tag, packen und nach Hause gehen, ja?

Warte! Nicht so schnell! Es gibt MEHR!

Da wir uns gut darüber fühlten, wie das alles gelaufen war, entschied ich mich spontan, um zu sehen, ob mein vorheriger Versuch mich immer noch in die Luft jagte und zum ersten Pythonstück in diesem Beitrag zurückkehrte. (Mit dem neuen C-Code natürlich) und ... es hat funktioniert! Die Ergebnisse waren identisch mit der struct.pack-Version! Beeindruckend!

Dies bedeutet, dass Ihre Benutzer die Wahl haben, wie sie diese Art von Daten bereitstellen möchten, und Ihr Code kann entweder ohne Änderungen umgehen. Persönlich werde ich die ctype.Structure-Methode fördern, da ich denke, dass es für eine bessere Lesbarkeit sorgt, aber es ist wirklich, was auch immer der Benutzer sich wohl fühlt. (Heck, sie könnten manuell eine Zeichenkette in Hex eingeben, wenn sie es wollten. Es funktioniert. Ich habe es versucht.)

Ehrlich gesagt denke ich, dass dies das bestmögliche Ergebnis ist, also bin ich ekstatisch. Vielen Dank noch einmal, und viel Glück an alle anderen, die auf dieses Problem stoßen!

    
Toji 21.02.2010, 20:07
quelle

2 Antworten

2

Nicht getestet, aber Sie sollten dies versuchen und lassen Sie uns wissen, wenn es schnell genug für Ihre Bedürfnisse ist.

Python-seitig packen Sie die Scheitelpunkte in eine Zeichenfolge anstelle eines Objekts.

%Vor%

Ändern Sie auf der C-Bibliothek / dem Python-Wrapper Ihr PyArgs_ParseTuple, um die Formatzeichenfolge "si" zu verwenden. Dies konvertiert Ihre Python-Zeichenfolge in eine C-Zeichenfolge (char *), die Sie dann als Zeiger auf Ihre Vektorstruktur typisieren können. An diesem Punkt ist die C-Zeichenfolge ein Stream von Bytes / Wörtern / Floats und sollte das sein, wonach Sie suchen.

Viel Glück!

    
Sam Post 22.02.2010, 03:51
quelle
1

Das Einfachste, was ich sehen kann, wäre, das Problem einfach zu vermeiden und eine Device_ReadVertex zu exponieren, die x, y, z, u, v und Farbe als Argumente akzeptiert. Dies hat offensichtliche Nachteile, wie zum Beispiel, dass die Python-Programmierer ihre Scheitelpunkte einzeln einspeisen.

Wenn das nicht gut genug ist (scheint es wahrscheinlich nicht), dann könnten Sie versuchen, einen neuen Python-Typ zu definieren, wie beschrieben hier . Es ist ein bisschen mehr Code, aber ich denke, das ist die "architektonisch solide" Methode, weil Sie sicherstellen, dass Ihre Python-Entwickler die gleiche Typdefinition verwenden wie im C-Code. Es erlaubt auch ein bisschen mehr Flexibilität als eine einfache Struktur (es ist wirklich eine Klasse, mit der Möglichkeit, Methoden hinzuzufügen, etc.), die ich nicht sicher bin, dass Sie tatsächlich brauchen, aber es könnte später nützlich sein.

    
xitrium 22.02.2010 04:02
quelle