Beispiel für die Verwendung von PyDict_GetItem

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

Hallo,
ich möchte PyDict_GetItem dazu verwenden ein Dictionary an eine C-Funktion zu übergeben.
In dem Dictionary sind die Parameter für die Funktion enthalten.
Diese muss ich also dann anhand der bekannten keys auslesen und in einer C-Variablen ablegen.
Vorher hatte ich es mit einem Tupel gemacht was ich zerlegt habe.
Ein Dictionary ist aber für mich günstiger, da ich damit die Fuktion dynamisch aufrufen kann.
So übergebe ich dann immer ein Objekt vom Typ dict an eine beliebige Funktion.

Weiss jemand ein Beispiel für die Verwendung von PyDict_GetItem?

Bitte keine Hinweise ich sollte alles komplett anders machen. :shock:
BlackJack

@hypnoticum: In Anbetracht der Kürze eines solchen Beispiels und den Änderungen die man daran vornehmen sollte -- nämlich mindestens die Funktion verwenden, die gleich nach `PyDict_GetItem()` in der Dokumentation beschrieben wird, kann man auf die Frage nicht antworten ohne den letzten Satz von Dir zu missachten. ;-)
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

@BlackJack:
"in DER Dokumentation"? welche Doku meinst du - ich habe nur in http://docs.python.org/c-api/dict.html und http://docs.python.org/c-api/concrete.html nachgesehen.
Ineressant wäre für mich wie ich dann die einzelnen Values in die C-Varablen kriege, also zB eine Typkonversion von PyObject nach int oder char*.
mache ich das am besten mit (int)PyInt_AsLong() und PyString_AsString()?
BlackJack

@hypnoticum: Genau die Dokumentation meinte ich. Du hast die Schlüssel ja als C-Zeichenketten vorliegen, da macht es Sinn sich den Umweg über eine Python-Zeichenkette zu sparen. Letztendlich würde ich aber anstelle der `PyDict_*`-Funktionen auf `PyMapping_*` zurück greifen. Denn die setzen auch eine Ausnahme wenn ein Schlüssel nicht gefunden wird. Dann muss man sich darum nicht selber kümmern.

Und ja, man muss die `PyObject`\s mit den entsprechenden Funktionen in C-Datentypen umwandeln.

Und dabei nicht die Fehlerbehandlung und die Referenzzähler vergessen.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

ich mache noch was falsch, ausserdem wäre es mal interessant zu wissen wie man eine Extension mit Eclipse am besten debuggen kann.

Code: Alles auswählen

PyObject *dict = NULL, *key = NULL, *PyDictVal = NULL;
char* paramArray[] = {"Param_A", \
			"Param_B", \
			"Param_C", \
			"Param_D", \
			"Param_E", \
			"Param_F", \
			"Param_G", \
			"Param_H"};

char *ResultFile;

PyArg_ParseTuple(args, "Os", &dict, &ResultFile);

int i, k;
for (i = 0; i < 8; i++){
	key = PyString_FromString(paramArray[i]);
	PyDictVal = PyDict_GetItem(dict, key);
	k = (int)PyInt_AsLong(PyDictVal);
	printf("%d\n", k);
}
Zuletzt geändert von hypnoticum am Freitag 29. April 2011, 12:18, insgesamt 2-mal geändert.
BlackJack

@hypnoticum: Du hast da auf jeden Fall weder Fehlerbehandlung noch Speicherverwaltung drin. Wenn irgend etwas davon nicht klappt, weil zum Beispiel ein Schlüssel nicht in den Argumenten vorhanden ist, arbeitest Du fröhlich mit NULL-Pointern weiter -- was zu Abstürzen des Python-Interpreters führen kann.

Und in der Schleife werden 8 `str`-Objekte erzeugt, die nicht wieder freigegeben werden. Da hast Du also ein Speicherleck.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

@BlackJack:
Danke für die Tips, aber solange die Funktion nicht läuft ist es weniger sinnvoll sich um Speicherverwaltung und Fehlerbehandlung zu kümmern.
BlackJack

@hypnoticum: Vielleicht kann man die Speicherverwaltung erst einmal vernachlässigen -- zumindest in eine "Richtung". Wenn Speicher von Objekten freigegeben wird, die man noch verwendet, dann kann das ja durchaus ein Problem sein.

Die Fehlerbehandlung sollte aber nicht weglassen werden, denn das ist ja *die* Chance heraus zu finden wo ein Problem liegt.

Grundsätzlich sollte die Funktion so "funktionieren", vorausgesetzt man ruft sie mit den richtigen Werten auf. Macht man das nicht kann von einem falschem Ergebnis bis Absturz alles mögliche passieren.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

@BlackJack:
funktioniert aber leider nicht.
ich bekomme die keys in das 'key'-Objekt und kann auch mit 'PyDictVal' referenzierte Werte als 'k' ausgeben. Nur PyDict_GetItem kriege ich nicht ans laufen.
mit der gezeigten Funktion bekomme ich für jeden Durchlauf nur '-1' zurück.
BlackJack

@hypnoticum: Dann schau doch mal in der Dokumentation was `PyInt_AsLong()` zurück gibt. Insbesondere was eine -1 bedeuten kann. Wenn Du das überprüfst und die Funktion dann entsprechend beendest bekommst Du eine schöne Ausnahme mit einem Fehlertext der ziemlich genau sagt was das Problem ist.

Wenn ich an den Inhalt der Dictionaries denke, welche Du an anderer Stelle hier gezeigt hast, dann habe mal die starke Vermutung, dass es ein ``TypeError: an integer is required`` sein wird. Und man sollte die Ausnahme durch eine ersetzen, die das Problem noch etwas besser beschreibt. Zum Beispiel zu welchem Schlüssel dieser Wert gehört.

Immer vorausgesetzt das Problem ist nicht schon vorher im Programmablauf und `PyInt_AsLong()` wird schon mit einem total ungültigen Wert aufgerufen.

Du *musst* Fehlerbehandlung betreiben. Die Dokumentation sagt, dass die meisten Funktionen die einen PyObjekt-Zeiger erwarten, *nicht* damit rechnen, dass der NULL ist und das der Interpreter in einem undefinierten Zustand ist, wenn man das trotzdem tut. Da kann dann alles mögliche passieren. Und das muss nicht einmal sofort auffallen, sondern kann auch erst später im Programmablauf passieren. Da wünsche ich dann viel Spass beim Fehlersuchen.

Und da Fehlerbehandlung sehr eng mit der Speicherverwaltung zusammen hängt -- im Fehlerfall muss man ja "aufräumen" bevor man die Funktion verlässt -- sollte man das auch gleich von Anfang an ordentlich mit erledigen.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

@BlackJack:
OK, ich habe in den values des dict halt doch anstelle von Integern Strings übergeben. Sry
Antworten