C++ ObjectWrapper für Python

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
DonnerCobra
User
Beiträge: 53
Registriert: Mittwoch 9. April 2008, 19:35

Hallo, ich möchte gerne einen ObjectWrapper schrieben. Ich möchte auch kein Boost nutzen, sondern das ganze mit der StandardBibliothek erreichen...



Enhalten ist 1x eine Funktion die etwas ausgibt. Und zwar "println" und dann wollte ich noch versuchen mittels ein paar Samples aus dem Internet einen ObjectWrapper für mein Objekt zu schreiben. Leider scheiter ich jedoch. Kann mir jemand helfen?

Danke!! Oder wo ich eventuell alternative SourceCodes herbekomme damit ich mir das ganze an einem Beispiel klarmachen kann.


Code: Alles auswählen


#include <Python/Python.h>
#include <string.h>

using namespace std;

//Function to print out something///////////////////////////////////////////
PyObject* println(PyObject* pSelf, PyObject* pArgs)
{
	char* s = NULL;
	if (!PyArg_ParseTuple(pArgs, "s", &s)) return NULL;
	printf("%s",s);
	
	Py_INCREF(Py_None);
	return Py_None;
}

static PyMethodDef myMethods[] = {
    {"println", println, METH_VARARGS},
    {NULL, NULL, 0, NULL}
};








////////CLASS WRAPPER!!!!!//////////////////////////////////////////////

class Numbers
{
public:
    Numbers(int first, int second)
	{
		m_first = first;
		m_second = second;
	}
    double NumMemberMult(void){ return m_first*m_second;}
private:
    int m_first;
    double m_second;
};

static void PyDelNumbers(void *ptr)
{
    //std::cout<<"Called PyDelNumbers()\n"; //Good to see once
    Numbers * oldnum = static_cast<Numbers *>(ptr);
    delete oldnum;
    return;
}

PyObject *wrap_new_Numbers(PyObject *, PyObject* args)
{
    //First, extract the arguments from a Python tuple
    int arg1;
    int arg2;
    int ok = PyArg_ParseTuple(args,"ii",&arg1,&arg2);
    if(!ok) return 0;
 
    //Second, dynamically allocate a new object
    Numbers *newnum = new Numbers(arg1, arg2);

    //Third, wrap the pointer as a "PyCObject" and
    // return that object to the interpreter
    return PyCObject_FromVoidPtr( newnum, PyDelNumbers);
}
////////////////////////////////////

int main (int argc, char **argv) {

	Py_Initialize();
	
	PyObject *m = Py_InitModule("c4d", myMethods);
	Py_INCREF((PyObject *)&wrap_new_Numbers);
    PyModule_AddObject(m, "Numbers", (PyObject *)&wrap_new_Numbers);

	PyRun_SimpleString("from c4d import *;\nprintln('ich bin ein test');\ntest = Numbers(3,4)");

	Py_Finalize();
    return 0;
}
DonnerCobra
User
Beiträge: 53
Registriert: Mittwoch 9. April 2008, 19:35

Hallo,

es hat alles geklappt und ich kann in Python nun ein Objekt erzeugen vom Typ Numbers.

heißt t = Numbers(3,4); jedoch funktioniert



Mit welchem Befehl füge ich denn hinzu, dass Python die Attribute (Member) meiner Klasse kennt? Mit PyMethodDef jedenfalls nicht, oder?


Danke sehr :)
Benutzeravatar
Spaten
User
Beiträge: 52
Registriert: Samstag 27. Mai 2006, 11:35
Wohnort: Bremen
Kontaktdaten:

Hallo DonnerCobra,

entschuldigung, dass ich diesen alten Thread noch einmal belebe,
aber ich bin im Moment mit einem ähnlichen Problem beschäftigt.
Ich möchte eine C++ Klasse für Python wrappen und habe mich
an deinem Beispiel orientiert. Das ganze lässt sich auch kompilieren
und linken, allerdings bekomme ich bei der Ausführung eine
Speicherzugriffsverletzung (segmentation fault) in der Zeile mit

Py_INCREF((PyObject *)&wrap_new_Numbers);

bzw. in der danach (PyModule_AddObject), wenn ich die Zeile davor auskommentiere.

Du hast gesagt, dass es bei dir funktioniert und es würde mich interessieren,
ob du noch etwas an dem oben geposteten Code verändert hast, damit es läuft.

Wäre echt nett, auch wenn jemand anders vielleicht einen Tipp hätte,
was die Zugriffsverletzung hervorrufen könnte.


Ich nutze DevCpp und Python 2.5
Python-Version: 2.5
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Der Zeiger auf die C-Funktion wrap_new_Numbers wird als Zeiger auf ein PyObject verwendet. Das muss wohl zwangsläufig zu Fehlern führen.
MfG
HWK

Edit: Diese beiden Links sollten Dir eigentlich ausreichend Anregungen geben: Link 1 und Link 2
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

Spaten hat geschrieben: Wäre echt nett, auch wenn jemand anders vielleicht einen Tipp hätte,
Würde jetzt auf die Schnelle sagen..

MyNumbers.cpp

Code: Alles auswählen

#include </usr/include/python2.5/Python.h>
#include <string.h>


PyObject *println(PyObject *self, PyObject *args)
{
    char *s = NULL;
    if (!PyArg_ParseTuple(args, "s", &s)) return NULL;
    printf("%s\n",s);

    Py_INCREF(Py_None);
    return Py_None;
}

class Numbers
{
public:
    Numbers(int first, double second)
       {m_first = first; m_second = second;}
    double NumMemberMult(void){ return m_first*m_second;}
private:
    int m_first;
    double m_second;
};

static void PyDelNumbers(void *ptr)
{
    Numbers * oldnum = static_cast<Numbers *>(ptr);
    delete oldnum;
    return;
}

PyObject *wrap_Numbers_MemberMult(PyObject *self, PyObject *args)
{
    // First, get the PyCObject from the args tuple
    PyObject *pynum = 0;
    int ok = PyArg_ParseTuple( args, "O", &pynum);
    //"O" is for Object
    if(!ok) return NULL;

    // Convert the PyCObject to a void pointer:
    void * temp = PyCObject_AsVoidPtr(pynum);
    // Cast the void pointer to a Numbers pointer:
    Numbers * thisnum = static_cast<Numbers *>(temp);

    //Second, make the function call
    double result = thisnum->NumMemberMult();

    //Third, build & return a Python float object
    return Py_BuildValue("d",result);
}

PyObject *wrap_new_Numbers(PyObject *self, PyObject *args)
{
    //First, extract the arguments from a Python tuple
    int arg1;
    double arg2;
    int ok = PyArg_ParseTuple(args,"id",&arg1,&arg2);
    if(!ok) return 0;

    //Second, dynamically allocate a new object
    Numbers *newnum = new Numbers(arg1, arg2);

    //Third, wrap the pointer as a "PyCObject" and
    // return that object to the interpreter
    return PyCObject_FromVoidPtr( newnum, PyDelNumbers);
}

////////////////

static PyMethodDef myFunc[] = {
    {"println", println, METH_VARARGS},
    {"Numbers",wrap_new_Numbers, METH_VARARGS},
    {"mult",wrap_Numbers_MemberMult, METH_VARARGS},
    {NULL, NULL, 0, NULL}
};



PyMODINIT_FUNC initMyNumbers()
{
    Py_Initialize();

    PyObject* m;
    m = Py_InitModule("MyNumbers", myFunc);
}
setup.py

Code: Alles auswählen

from distutils.core import setup, Extension

mynum = Extension('MyNumbers',
                    sources = ['MyNumbers.cpp'])

setup (name = 'MyNumbers',
       version = '0.1',
       description = 'This is a test package',
       ext_modules = [mynum])
python setup.py install

Code: Alles auswählen

>>> from MyNumbers import *
>>> n = Numbers(9,9)
>>> n
<PyCObject object at 0xb7de9440>
>>> mult(n)
81.0
>>>
Benutzeravatar
Spaten
User
Beiträge: 52
Registriert: Samstag 27. Mai 2006, 11:35
Wohnort: Bremen
Kontaktdaten:

Vielen Dank für die Info!

Hat geklappt, danke :D
Python-Version: 2.5
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

Hallo,

ich habe eine Frage zur Verwendung von "PyArg_ParseTuple".

Ich moechte ein Array/Liste/Tuple (eigentlich wurst was es am Ende wird) an ein C++-Array weitergeben.

Wenn ich jetzt ein Tuple in Python erzeuge:

Code: Alles auswählen

 
def testFunc():
    return tuple([1,2])
und im C++-Code nehme ich das mit der Zeile

Code: Alles auswählen

pValueTuple = PyObject_CallObject(pFunc, pArgs);
PyObject *testTuple;
if (PyTuple_Check(pValueTuple)){
    PyArg_ParseTuple(pValueTuple, "O", &testTuple);
    std::cout << PyTuple_Check(testTuple) << std::endl;
}
Dabei sind pValueTuple, pFunc und pArgs PyObject *

Dann gibt es erzeugt das einen Windows Fehler. Die einzige Moeglichkeit wie man das ohne Fehler zum laufen kriegt (wenigstens die einzige die ich gefunden habe) ist z.B.

Code: Alles auswählen

return tuple([1])
zurueck zugeben. Allerdings gibt der Test ob "testTuple" zurueck, dass es sich _nicht_ um ein Tuple handelt (0). Sobald man ein mehrelementiges Tuple ausgibt stuerzt das Program ab.

Irgendwer eine Idee? Oder eine andere Moeglichkeit ein Array aus Python an C++ zu uebergeben?

Vielen Dank fuer die Antworten
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Hoi,

sorry, aber ich kapiere Deine Frage schon nicht. Möchtest Du vielleicht wissen wie man eine Liste / einen Tuple als Parameter an eine Funktion in C/C++ übergibt?

Falls nicht und niemand anders hier weiß, was Du möchtest, solltest Du vielleicht schreiben, was die testFunc mit dem C-Code zu tun hat - das ist quasi ein boolean auf dem Terminal ausgeben. Oder was ist der Zweck?

Gruß,
Christian
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

CM hat geschrieben:Hoi,
Möchtest Du vielleicht wissen wie man eine Liste / einen Tuple als Parameter an eine Funktion in C/C++ übergibt?
Christian
Genau das moechte ich. Es laeuft einfach drauf raus, dass ich ein Numpy-Array (2d) ausgebe und es an C/C++ uebergebe.

Ich habe gesehen, dass die Funktionen PyArg_Parse() und PyArg_ParseTuple() gibt. Wenn ich aus python also ein tuple ausgebe, dann kann ich das mit PyArg_Parse(pythonTuple, "O", &pyObj) uebergeben (das geht erstaunlicherweise mit PyArg_ParseTuple nicht!). Was ich dann in pyObj habe ist auch tatsaechlich ein Tuple.

Inzwischen gehe ich den unschoenen/komplizierten Weg und initalisiere ein 2d-C/C++-Array und schreibe die Elemente des Tuples einzeln mit PyTuple_GetItem().

Ich dachte es gibt eine elegante Moeglichkeit direkt das Numpy-Array aus python an ein C/C++-Array zurueck zu geben. Habe aber bisher keine gefunden.

Richtig bloed wird es, wenn man ein Tuple von Tuplen zurueck geben moechte, das geht zwar, aber man muss PyArg_Parse(pythonTuple, "OOO..", &pyObj1, &pyObj2, &pyObj3,...) aufrufen. Wenn man sich jetzt aber nicht auf die Anzahl der Tuple-Elemente in dem zurueckgegebenen Tuple festlegen moechte, dann geht das so nicht (weil man ja PyArg_Parse sagen muss wieviele Elemente da in welchem Format kommen). Auch hier waere ein Funktionsaufruf PyArg_Parse(numpyArray,"?", &initalized2dArray). Nur das es "?" eben nicht gibt. :roll:

Fazit: Ich bekomme es hin, es ist aber nicht optimal (Geschwindigkeit etc.) und auch nicht schoen.
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

Ich dachte es gibt eine elegante Moeglichkeit direkt das Numpy-Array aus python an ein C/C++-Array zurueck zu geben. Habe aber bisher keine gefunden.
Klar geht das. Hir mal ein Ausschnitt aus einem Modul das ich mal geschrieben hab:

Code: Alles auswählen

static PyObject *_ImageProcessing_median(PyObject *self, PyObject *args)
{ 
    PyArrayObject *a;		//in
	PyArrayObject *mask;	 //in
	PyArrayObject *b;		//out
	int cx, cy;			  //in, center point mask

	if(!PyArg_ParseTuple(args, "O!O!ii", &PyArray_Type, &a, &PyArray_Type, &mask, &cy, &cx)) return NULL; 

	int * mask_ptr = PyArray_DATA(mask);
Die ersten beiden Argumente sind numpy.array's. Die numpy API stellt eine Reihe von Makros und Funktionen bereit, die dir den Zugriff auf das Array ermöglichen. Wenn du einen Pointer auf die eigentlichen Daten haben willst, geschieht das so wie in Zeile 10. Hier findest du die Doku der Zugriffsmethoden. Damit die C-API richtig funktioniert, darfst du folgendes nicht vergessen.

Code: Alles auswählen

#include <Python.h>
#include "numpy/arrayobject.h"  // !!!!!

...

// Modul-Initialisierung
PyMODINIT_FUNC init_ImageProcessing(void) 
    { 
    Py_InitModule("_ImageProcessing", _ImageProcessingMethods);
    import_array(); // !!!!!!!
    }
MFG HerrHagen
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

HerrHagen hat geschrieben:

Code: Alles auswählen

	if(!PyArg_ParseTuple(args, "O!O!ii", &PyArray_Type, &a, &PyArray_Type, &mask, &cy, &cx)) return NULL; 

	int * mask_ptr = PyArray_DATA(mask);
Habe ich eigentlich so gemacht. Bei der letzten Zeile bin ich mir nicht sicher ob das mit 2d-Arrays funktioniert. Muss ich mal noch ausprobieren.
HerrHagen hat geschrieben:

Code: Alles auswählen

#include <Python.h>
#include "numpy/arrayobject.h"  // !!!!!

...

// Modul-Initialisierung
PyMODINIT_FUNC init_ImageProcessing(void) 
    { 
    Py_InitModule("_ImageProcessing", _ImageProcessingMethods);
    import_array(); // !!!!!!!
    }
Vielen Dank fuer den Link. Die Modulinitialisierung kapiere ich noch nicht. Wahrscheinlich brauch ich das aber so auch nicht, weil ich kein static-Funktion benutze. Der ganze Code befindet sich in einer Funktion in einer DLL. Wie gesagt, ich muss mal rumprobieren und nachdenken. Vielen Dank fuer die Hilfe.
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

Bei der letzten Zeile bin ich mir nicht sicher ob das mit 2d-Arrays funktioniert.
Ja! Die Daten liegen dann (wenn du ein C-Array gemacht hast, nicht FORTRAN) Zeile für Zeile hintereinander. Du kannst das mit numpy.require(a, dtype='int32', requirements='CA') auch fordern.
Am besten solltest du aber auf die Daten nicht direkt über den DATA-Pointer sondern über die PyArray_GETPTR2(PyObject* obj, <npy_intp> i, <npy_intp> j) Funtkion gehen.
Die Modulinitialisierung kapiere ich noch nicht. Wahrscheinlich brauch ich das aber so auch nicht, weil ich kein static-Funktion benutze.
Die ist per Definition zwingend für jedes Erweiterungsmodul! Genauso wie alle Funktionen die du von Python aus nutzen willst static sein müssen. Ich hab nur die Stellen mit !!!! markiert, die zusätzlich bei der Benutzung der numpy-API anfallen. Schau dir einfach mal die Beispiele auf der scipy-Seite an.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

SCNR:
booth hat geschrieben:Genau das moechte ich. Es laeuft einfach drauf raus, dass ich ein Numpy-Array (2d) ausgebe und es an C/C++ uebergebe.
Genau *das* stand da vorher nicht. Aber schön, dass es jetzt gelöst ist ;-).

Gruß,
Christian
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

CM hat geschrieben:SCNR:
booth hat geschrieben:Genau das moechte ich. Es laeuft einfach drauf raus, dass ich ein Numpy-Array (2d) ausgebe und es an C/C++ uebergebe.
Genau *das* stand da vorher nicht. Aber schön, dass es jetzt gelöst ist ;-).
Wir brauchen mehr Praezesion :D

Ich muss mir erstmal die ganzen Beispiele etc. ansehen. Wenn ich nur nicht so langsam waere... :roll:
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

Das ist ja alles noch viel komplizierter als ich gedacht habe ;)
HerrHagen hat geschrieben:

Code: Alles auswählen

static PyObject *_ImageProcessing_median(PyObject *self, PyObject *args)
{ 
    PyArrayObject *a;		//in
	PyArrayObject *mask;	 //in
	PyArrayObject *b;		//out
	int cx, cy;			  //in, center point mask

	if(!PyArg_ParseTuple(args, "O!O!ii", &PyArray_Type, &a, &PyArray_Type, &mask, &cy, &cx)) return NULL; 

	int * mask_ptr = PyArray_DATA(mask);
Ich vestehe noch nicht wozu ich eigentlich ein Modul brauche. Kann ich Zeile 9 nicht einfach in der main()-Funktion aufrufen?
HerrHagen hat geschrieben:

Code: Alles auswählen

#include <Python.h>
#include "numpy/arrayobject.h"  // !!!!!

...

// Modul-Initialisierung
PyMODINIT_FUNC init_ImageProcessing(void) 
    { 
    Py_InitModule("_ImageProcessing", _ImageProcessingMethods);
    import_array(); // !!!!!!!
    }
Wahrscheinlich muss das Argument "_ImageProcessing_median" sein, oder? Gibt es bei dir dann noch eine Zeile ala:

Code: Alles auswählen

static PyMethodDef _ImageProcessingMethods[]
Und zu guter Letzt (vorerst). Wieso kann ich import_array() nicht einfach nach Py_Initialize(); aufrufen. Mein Compiler (mingw) meldet "statement with no value, in function returning 'int'". Was auch immer das heisst.

vG, U.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Hoi,
booth hat geschrieben:Ich vestehe noch nicht wozu ich eigentlich ein Modul brauche. Kann ich Zeile 9 nicht einfach in der main()-Funktion aufrufen?
Welche main() ? Reden wir gerade über extending oder embedding? Wie auch immer: Die Antwort ist eher nein, es sei denn, Du machst seltsame Verrenkungen.
booth hat geschrieben:
Wahrscheinlich muss das Argument "_ImageProcessing_median" sein, oder? Gibt es bei dir dann noch eine Zeile ala:

Code: Alles auswählen

static PyMethodDef _ImageProcessingMethods[]
Und zu guter Letzt (vorerst). Wieso kann ich import_array() nicht einfach nach Py_Initialize(); aufrufen. Mein Compiler (mingw) meldet "statement with no value, in function returning 'int'". Was auch immer das heisst.

vG, U.
Jupp, es müsste etwas geben, das so aussieht:

Code: Alles auswählen

static PyMethodDef _ImageProcessingMethods[] {
  { name als string, Funktionsname , METH_VARARGS oder Vergleichbares, Docstring},
  {Senitnel} /* z. B. {NULL, NULL, NULL, NULL} */
}
Py_Initialize() riecht schon wieder so nach embedding - möchstest Du das machen? Ansonsten wirst Du eher PyMethodDef wollen.

HTH
Christian
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

Nochmal in kurz was ich machen moechte (Code kommt unten).

1. Ich brauche eine dll (geht nicht anders). Zum testen tuts aber ein kleines Programm.exe. Die dll stellt eine Funktion zur Verfuegung, die als Parameter ein 2d Array hat. Damit ist das Ganze nur als Embedding zu machen, oder?

2. An die dll (oder fest in der main() definiert) uebergebe ich einen String, der an ein Python-Skript uebergeben wird zwecks regular expressions und numpy

3. Das Skript wertet den String aus und gibt mir ein numpy-Array zurueck.

4. Ich schreibe das numpy-Array in das C++-Array (Eingabeparameter der dll-Funktion).

Bei dem Code den ich bisher geschrieben habe halte ich mich ziemlich an die Vorlagen auf doc.python.org

Cheerio.

[Edit] Hier jetzt noch der Code, der nicht funktioniert:

Code: Alles auswählen

#include <iostream>
#include "Python.h"
#include "arrayobject.h"

int main()
{
	char *patternString = "pattern(10,100,8,1,2,3,4,5,6,7,8)";
	PyObject *pName, *pModule, *pFunc;
	PyObject *pArgs, *pValueTuple;

	Py_Initialize();
	import_array();

	/* Error checking of pName left out */
	pName = PyString_FromString("pattern"); // Name of the python file (pattern.py)
	pModule = PyImport_Import(pName); 
	Py_DECREF(pName);

	if (pModule != NULL) {
		pFunc = PyObject_GetAttrString(pModule, "numpyA"); // Call function from module
		/* pFunc is a new reference */

		pArgs = PyTuple_New(1); // Arguments to call function with. 
		PyTuple_SetItem(pArgs, 0, PyString_FromString(patternString)); // Fill argument tuple

		if (pFunc && PyCallable_Check(pFunc)) {
			pValueTuple = PyObject_CallObject(pFunc, pArgs);
			Py_DECREF(pArgs);

			PyArrayObject *a;
			PyArg_Parse(pValueTuple, "O!", &PyArray_Type, &a);
			//std::cout << PyTuple_Check(testTuple1) << std::endl;
			Py_XDECREF(a);
			Py_XDECREF(pValueTuple);
		}
		else { // Either pFunc is not a function or not callable. A problem anyway
			if (PyErr_Occurred())
				PyErr_Print();
			fprintf(stderr, "Cannot find function \"%s\"\n", "getValues");
		}
		Py_XDECREF(pFunc); // XDECREF decrement the count for pFunc. Same as DECREF, but argument is allowed to be NULL
		Py_DECREF(pModule);
	}
	else {
		PyErr_Print();
		fprintf(stderr, "Failed to load \"%s\"\n", "pattern.py");
		return 1;
	}
	Py_Finalize();
	return 0;
}
Und das Python-Skript

Code: Alles auswählen

from numpy import *

def numpyA(inSdump):
    a = array([1,2,3,4,5],[5,4,3,2,1])
    return a
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

booth hat geschrieben:1. Ich brauche eine dll (geht nicht anders). Zum testen tuts aber ein kleines Programm.exe. Die dll stellt eine Funktion zur Verfuegung, die als Parameter ein 2d Array hat. Damit ist das Ganze nur als Embedding zu machen, oder?
Nein, das ist in sich widersprüchlich: Wenn Du eine dll (oder ein shared object (.so) unter Linux) willst, die eine Funktion zur Verfügung stellt, die Du in Python importieren kannst, dann ist das nicht embedding, sondern extending - und zwar von Python. Mit embedding bezeichnet man das "Einbauen" von Python in ein anderes (C/C++)-Programm. Ergo brauchst Du auch kein Executable, sondern nur die dll, deren Funktion Du importierst.
booth hat geschrieben:2. An die dll (oder fest in der main() definiert) uebergebe ich einen String, der an ein Python-Skript uebergeben wird zwecks regular expressions und numpy
Wieso das? Wieso ein String, wenn es ein numpy array sein soll?
booth hat geschrieben:3. Das Skript wertet den String aus und gibt mir ein numpy-Array zurueck.
Wie auch immer, wenn Du einen String an eine Funktion in C++ übergeben willst und ein numpy-Array zurückkommen soll, dann mußt Du letzters erst erzeugen. Das ginge z. B. mit PyArray_NewFromDescr oder PyArray_New und Konsorten. Aber Du gibst ja gar nichts zurück - außer einem Integer.
booth hat geschrieben:4. Ich schreibe das numpy-Array in das C++-Array (Eingabeparameter der dll-Funktion).
Also da blicke ich nicht so ganz durch:
Du deklarierst patternString und steckst es in eine Funktion, die einen Parameter akzeptiert, aber diesen nicht, sondern - wenn man von dem Fehler (s.u.) absieht - ein anderes array zurückgibt. (Tipp: Mit "inSdump" passiert gar nichts.)

In dem Python-Skript erzeugst Du kein Array, es sei denn Du hast numpy.ndarray umgeschrieben ;-). Bei mir erzeugt

Code: Alles auswählen

array([1,2,3,4,5],[5,4,3,2,1])
einen Traceback:

Code: Alles auswählen

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: data type not understood
Warum zeigt Dir

Code: Alles auswählen

>>> help(array)
Wenn Du tatsächlich ein 2d-array erzeugen willst, dann z. B. so:

Code: Alles auswählen

array([[1,2,3,4,5],[5,4,3,2,1]])
So, jetzt kannst Du entweder die Pythonfunktion entsprechend ändern, damit Du tatsächlich mit den Werten so arbeitest, wie Du es wünscht. Oder, falls Dein Wunsch ist von Python aus auf kompilierte Funktionen zurückgreifen zu können, solltest Du im C-Code tatsächlich auch Funktionen deklarieren (und definieren sowieso ;-) ). Wie, hat HerrHagen gezeigt.

Gruß,
Christian

PS Vielleicht solltest Du demnächst nicht alte Threads wiederbeleben, um dort Fragen zu stellen, die nicht zum Kontext passen. Das verwirrt und hilft Dir erst einmal nicht weiter und anderen im Forum, diie suchen, auch nicht.
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

Hmm. Scheinbar schaffe ich es nicht mich klar auszudruecken. Sorry.

Ich moechte keine C++-Funktion in Python benutzen. Also nicht extending, sondern Python-Funktionen in C++ einbinden (verstehe ich unter embedding). Also, ich moechte aus C++ eine Pythonfunktion aufrufen (mit zB einem String als Parameter) und etwas aus Python zurueckbekommen (naemlich das array).

Wie genau aus dem string ein Array wird habe ich rausgelassen weil nicht interesant und auch nicht auf den Syntax geachtet (sorry). Wie gesagt, der Code funktioniert nicht, er sollte nur illustrieren, was ich machen will. Das der input-String nicht benutzt wird ist zur Zeit so gewollt, ist ja nur ein Testprogramm, dass dann erweitert wird, wenn die erste Zeile mal tut :)

Zum Thema altes Thread wiederbeleben. Ich scheue mich immer davor neue Threads aufzumachen, da meistens die ersten beiden Seiten nur Kommentare im Stil von "Benutz die Suche" enthalten. Ich fand meint Thema passte gut in diesen Thread. Werde ich in Zukunft dann anders machen.
booth
User
Beiträge: 44
Registriert: Mittwoch 31. Oktober 2007, 21:30
Wohnort: Durham, U.K.

O.K. Hab's hingekriegt. Der Vollstaendigkeit halber (vielleicht hilft's ja mal wem) hier der Code, auch wenn der nichts Sinnvolles macht. Ausserdem enthaelt er kaum Fehlerroutinen. :roll:

Kurzbeschreibung: Der Code ruft ein Python-Skript (pattern.py) auf. Selbiges gibt ein numpy-Array zurueck, dass dann auf die Console ausgegeben wird.

Edit Programm auf Grund der Empfehlungen in den Folgekommentaren abgeaendert.

Code: Alles auswählen

#include <iostream>
#include "Python.h"
#include "arrayobject.h"

int main()
{
	PyObject *pName, *pModule, *pFunc;
	PyObject *pValue;

	Py_Initialize();
	_import_array();

	pName = PyString_FromString("pattern"); // Name of the python file (pattern.py)
	pModule = PyImport_Import(pName); 
	Py_DECREF(pName);

	if (pModule != NULL) {
		pFunc = PyObject_GetAttrString(pModule, "numpyA"); // Call function from module
		
        if (pFunc && PyCallable_Check(pFunc)) { // If pFunc exists and is callable, than it's a function and we can proceed
				pValue = PyObject_CallObject(pFunc, NULL); // Call function with no arguments, return value to a python variable

				// Schreiben des Arrays
				if (PyArray_Check(pValue)){
					for (int ic=0; ic<PyArray_DIM(pValue,0); ic++){
						for (int jc=0; jc<PyArray_DIM(pValue,1); jc++){
							std::cout << *(double*) PyArray_GETPTR2(pValue, ic, jc) << std::endl;
						}
					}
					Py_XDECREF(pFunc); // XDECREF decrement the count for pFunc. Same as DECREF, but argument is allowed to be NULL
					Py_DECREF(pModule);
				}
				else {
					Py_XDECREF(pFunc);
					Py_DECREF(pModule);
					if (PyErr_Occurred())
						PyErr_Print();
					fprintf(stderr, "Function \"%s\" didn't return a numpy array!\n", "getValues");
					return 1;
				}
			}
				else {
					Py_XDECREF(pFunc);
					Py_DECREF(pModule);
					if (PyErr_Occurred())
						PyErr_Print();
					fprintf(stderr, "Function \"%s\" didn't return a numpy array!\n", "getValues");
					return 1;
				}
			}
			else { // Either pFunc is not a function or not callable. A problem anyway
				Py_XDECREF(pFunc);
				Py_DECREF(pModule);
				if (PyErr_Occurred())
					PyErr_Print();
				fprintf(stderr, "Cannot find function \"%s\"\n", "getValues");
				return 1;
			}
		Py_XDECREF(pFunc);
		Py_DECREF(pModule);
	}
	else {
		PyErr_Print();
		fprintf(stderr, "Failed to load \"%s\"\n", "pattern.py");
		return 1;
	}
	Py_Finalize();
	return 0;
}
Und dann noch der ebenfalls etwas sinnlose Python-Code fuer pattern.py:

Code: Alles auswählen

from numpy import *

# Function definition
def numpyA(inSdump): # Inputstring noch unnuetz.
    a = array([[1.1,2.1,3.1,4.1,5.1],[5.2,4.2,3.2,2.2,1.2]])
    return a
Vielen Dank fuer eure Hilfen!
Zuletzt geändert von booth am Freitag 13. Februar 2009, 10:40, insgesamt 3-mal geändert.
Antworten