builtin array von c ext function zurückgeben

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.
Antworten
iwl
User
Beiträge: 12
Registriert: Samstag 9. Dezember 2006, 16:11

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?
BlackJack

Ein "builtin array" gibt's AFAIK nicht. Nur das `array`-Modul.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

... 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
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

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

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]
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

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
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

@iwl: Hast Du Dein Problem jetzt gelöst? Wenn ja, wie denn?
MfG
HWK
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

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
iwl
User
Beiträge: 12
Registriert: Samstag 9. Dezember 2006, 16:11

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.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

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
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

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
Antworten