Seite 1 von 1
builtin array von c ext function zurückgeben
Verfasst: Donnerstag 1. März 2007, 16:01
von iwl
Hallo Leute,
ich suche vergeblich ein Beispiel wie ich von einer C Extension Function ein Python builtin array zurueckgeben kann.
Ich möchte nicht NumPy installieren müssen, sondern das vorhandene benutzen, eine Zugriffsmöglichkeit von C ist aber nirgends so richtig dokumentiert.
Wer hat da einen Tip?
Verfasst: Donnerstag 1. März 2007, 16:30
von BlackJack
Ein "builtin array" gibt's AFAIK nicht. Nur das `array`-Modul.
Verfasst: Donnerstag 1. März 2007, 19:55
von CM
... und wie man das mit dem array-Modul macht weiß ich auch nicht, aber Du hast gute Chancen die Fragen unter comp.lang.python beantwortet zu bekommen.
HTH,
Christian
Verfasst: Donnerstag 1. März 2007, 23:03
von Joghurt
Verfasst: Freitag 2. März 2007, 09:06
von CM
Soweit ich verstanden habe, Joghurt, meint er
das array-Modul. Das API wird ähnlich sein, wie bei List Objects, aber die Frage scheint: Wie kann man erreichen, daß ein 'array' zurückgegeben wird? Hast Du da einen Link - ich habe nichts finden können.
Oder gibt es hier ein Mißverständnis? iwl, Deine Gelegenheit zur Klarstellung

.
Gruß,
Christian[/list]
Verfasst: Samstag 3. März 2007, 10:02
von HWK
Wahrscheinlich ist es am einfachsten, in C mit einem normalen C-Array zu arbeiten, das dann mit PyString_FromStringAndSize in einen Python-String umzuwandeln und an das Python-Script zurückzuliefern. Hier dürfte dann die Umwandlung in ein array, wenn sie denn überhaupt noch nötig sein sollte, kein Problem mehr sein.
Hier ein Beispiel:
Code: Alles auswählen
/* File CArray.c */
/* Python-String in C als C-Array bearbeiten. */
#include <Python.h>
static PyObject *carray(PyObject *self, PyObject *args)
{
char *str;
int slen, i;
if (!PyArg_ParseTuple(args, "s#", &str, &slen))
return NULL;
for(i = 0; i < slen; i++)
str[i] += 1; // Verändert direkt den Ausgangsstring
return PyString_FromStringAndSize(str, slen);
}
static PyMethodDef CArrayMethods[] = {
{"carray", carray, METH_VARARGS,
"Python-String in C als C-Array bearbeiten."},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initcarray()
{
Py_InitModule("carray", CArrayMethods);
}
Wenn man nicht den Ausgangsstring verändern will, muss man Speicher für den neuen String holen und wieder freigeben. Der Einfachheit halber habe ich für die Demo darauf verzichtet.
Code: Alles auswählen
# File setup.py
from distutils.core import setup, Extension
carray = Extension('carray', sources=['CArray.c'])
setup(name='carray', version='0.1',
description='Python-String in C als C-Array bearbeiten.',
ext_modules=[carray])
Code: Alles auswählen
# File CArray.py
from array import array
from binascii import hexlify
from carray import carray
text = '\x00\x5aHallo\xFF'
print hexlify(text)
print hexlify(carray(text))
array_ = array('c', text)
array_.reverse()
print array_
Und ein Beispiel mit Floats:
Code: Alles auswählen
from array import array
from binascii import hexlify
from struct import pack, unpack
from carray import carray
double = [1.0, 2.0, 3.0]
text = ''
for num in double:
text += pack('d', num)
print double
print hexlify(text)
print hexlify(carray(text))
for i in range(0, len(text) / 8):
double[i] = unpack('d', text[8 * i:8 * (i + 1)])
print double
array_ = array('d', text)
array_.reverse()
print array_
Das meiste dabei sind Anweisungen zur Ausgabe, die das Ergebnis verdeutlichen sollen. Der reine Datenaustausch kostet gerade mal 5 Zeilen.
MfG
HWK
Verfasst: Donnerstag 8. März 2007, 16:53
von HWK
@iwl: Hast Du Dein Problem jetzt gelöst? Wenn ja, wie denn?
MfG
HWK
Verfasst: Donnerstag 8. März 2007, 17:31
von CM
Hoi,
Deinen Lösungsvorschlag, HWK, finde ich erst einmal nicht schlecht. Aber mir ist noch eingefallen (hätte ich auch eher drauf kommen können

), das es da ja noch den
Quellcode des Arraymoduls gibt. Vielleicht hilft ein Blick dort hinein auch weiter.
Gruß,
Christian
Verfasst: Freitag 9. März 2007, 18:18
von iwl
HWK hat geschrieben:@iwl: Hast Du Dein Problem jetzt gelöst? Wenn ja, wie denn?
MfG
HWK
Code: Alles auswählen
[...]
#define Ret0 return NULL
[...]
PyObject * ps_ArrayFunc=0, * ps_fTuple=0;
#define DR Py_DECREF
static PyObject * ps_makePyFloatArray(float * buf, int values)
{ PyObject * PyBuf, * Func, * Tuple, * Array, * Ret;
if(!ps_ArrayFunc)
{ PyObject * Module = PyImport_ImportModule("array");
if(!Module) Ret0;
ps_ArrayFunc=PyObject_GetAttrString(Module, "array");
DR(Module);
if(!ps_ArrayFunc) Ret0;
}
if(!ps_fTuple) if((ps_fTuple=Py_BuildValue("(s)", "f"))==0) Ret0;
if((Array=PyObject_CallObject(ps_ArrayFunc, ps_fTuple))==0) Ret0;
if((Func=PyObject_GetAttrString(Array, "fromstring"))==0) { DR(Array); Ret0; }
if((Tuple=PyTuple_New(1))==0) { DR(Array); DR(Func); Ret0; }
if((PyBuf=PyBuffer_FromMemory(buf, values*sizeof(float)))==0)
{ DR(Array); DR(Func); DR(Tuple); Ret0; }
PyTuple_SetItem(Tuple, 0, PyBuf);
Ret=PyObject_CallObject(Func, Tuple);
DR(Func); DR(Tuple);
if(!Ret) Ret0;
DR(Ret);
return(Array);
}
//---------------------------------------------------------------------------
[...]
void initps(void)
{ ps_ArrayFunc=ps_fTuple=0;
[...]
Gerade kam mir noch die Idee den Buffer einfach als 2. Parameter an die array-funktion zu uebergeben, was die Sache vereinfachen würde, allerdings akzeptiert die array-function als 2. Parameter nur einen String und keinen Buffer, die fromstring-function dagegen akzeptiert einen Buffer, obwohl das so nicht dokumentiert ist.
Eigentlich sollte die array-funktion auch einen Buffer akzeptieren, das wäre wohl im Sinne des arrays, aber geht halt nicht.
Verfasst: Freitag 9. März 2007, 20:16
von HWK
Toll gemacht!
Ich glaub, ich hab's weitgehend verstanden. Die Referenzen erfordern ja doch ziemlich viel Aufmerksamkeit. Was mir noch unklar ist: Müsste man nicht array.fromstring() einen String und kein Tuple übergeben?
MfG
HWK
[Edit]: Funktioniert Deine Idee nicht doch, z.B. so (ungetestet)?
Code: Alles auswählen
[...]
#define Ret0 return NULL
[...]
PyObject * ps_ArrayFunc=0;
#define DR Py_DECREF
static PyObject * ps_makePyFloatArray(float * buf, int values)
{ PyObject * ps_fTuple, * Array;
if(!ps_ArrayFunc)
{ PyObject * Module = PyImport_ImportModule("array");
if(!Module) Ret0;
ps_ArrayFunc=PyObject_GetAttrString(Module, "array");
DR(Module);
if(!ps_ArrayFunc) Ret0;
}
if((ps_fTuple=Py_BuildValue("(ss#)", "f", buf, values*sizeof(float)))==0) Ret0;
if((Array=PyObject_CallObject(ps_ArrayFunc, ps_fTuple))==0) Ret0;
return(Array);
}
//---------------------------------------------------------------------------
[...]
void initps(void)
{ ps_ArrayFunc=0;
[...]
Py_BuildValue macht ja aus dem Buffer einen Python-String, den ich an array übergeben kann. Müsste ich dann eigentlich ps_fTuple am Schluss dereferenzieren?
MfG
HWK
Verfasst: Freitag 9. März 2007, 22:22
von HWK
Es klappt wirklich. Ich habe zum Testen mal mein erstes Beispiel entsprechend verändert:
Code: Alles auswählen
/* File CArray.c */
/* C-Array aus Floats in Python array.array umwandeln. */
#include <Python.h>
static PyObject *ps_ArrayFunc = NULL;
static PyObject *carray(PyObject *self, PyObject *args)
{
char *str;
int slen;
PyObject *ps_fTuple, *Array;
if (!PyArg_ParseTuple(args, "s#", &str, &slen))
return NULL;
if (!ps_ArrayFunc) {
PyObject *Module = PyImport_ImportModule("array");
if (!Module)
return NULL;
ps_ArrayFunc = PyObject_GetAttrString(Module, "array");
Py_DECREF(Module);
if (!ps_ArrayFunc)
return NULL;
}
if (!(ps_fTuple = Py_BuildValue("(ss#)", "d", str, slen)))
return NULL;
Array = PyObject_CallObject(ps_ArrayFunc, ps_fTuple);
Py_DECREF(ps_fTuple);
return(Array);
}
static PyMethodDef CArrayMethods[] = {
{"carray", carray, METH_VARARGS,
"C-Array aus Floats in Python array.array umwandeln."},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initcarray()
{
Py_InitModule("carray", CArrayMethods);
}
Code: Alles auswählen
# File CArray.py
from struct import pack
from carray import carray
double = [1.0, 2.0, 3.0]
text = ''
for num in double:
text += pack('d', num)
print double
print carray(text)
Somit ist es kaum länger als die Umwandlung in einen String, wenn man einmal vom notwendigen Importieren des array-Moduls absieht.
MfG
HWK