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 :roll: ), 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