Python tuple to C array - python

I am writing a C function that takes a Python tuple of ints as an argument.
static PyObject* lcs(PyObject* self, PyObject *args) {
int *data;
if (!PyArg_ParseTuple(args, "(iii)", &data)) {
....
}
}
I am able to convert a tuple of a fixed length (here 3) but how to get a C array from a tuple of any length?
import lcs
lcs.lcs((1,2,3,4,5,6)) #<- C should receive it as {1,2,3,4,5,6}
EDIT:
Instead of a tuple I can pass a string with numbers separated by ';'. Eg '1;2;3;4;5;6' and separate them to the array in C code. But I dont think it is a proper way of doing that.
static PyObject* lcs(PyObject* self, PyObject *args) {
char *data;
if (!PyArg_ParseTuple(args, "s", &data)) {
....
}
int *idata;
//get ints from data(string) and place them in idata(array of ints)
}

Use PyArg_VaParse: https://docs.python.org/2/c-api/arg.html#PyArg_VaParse
It works with va_list, where you can retrieve a variable number of arguments.
More info here: http://www.cplusplus.com/reference/cstdarg/va_list/
And as it's a tuple you can use the tuple functions: https://docs.python.org/2/c-api/tuple.html like PyTuple_Size and PyTuple_GetItem
Here's there's a example of how to use it: Python extension module with variable number of arguments
Let me know if it helps you.

Not sure if this is what you're looking for, but
you could write a C function that takes a variable number of arguments, using va_list and va_start.
A tutorial is here: http://www.cprogramming.com/tutorial/c/lesson17.html

I think I have found a solution:
static PyObject* lcs(PyObject* self, PyObject *args) {
PyObject *py_tuple;
int len;
int *c_array;
if (!PyArg_ParseTuple(args, "O", &py_tuple)) {
return NULL;
}
len = PyTuple_Size(py_tuple);
c_array= malloc(len*4);
while (len--) {
c_array[len] = (int) PyInt_AsLong(PyTuple_GetItem(py_tuple, len));
// c_array is our array of ints
}
}
This answer was posted as an edit to the question Python tuple to C array by the OP Piotr Dabkowski under CC BY-SA 3.0.

Related

SWIG -- Using typemap inside of extend

I have a c++ class written and I am using SWIG to make a Python version of my class. I would like to overload the constructor so that it can take in Python lists. For example:
>>> import example
>>> a = example.Array([1,2,3,4])
I was attempting to use the typemap feature in swig, but the scope of typemap does not include code in extend
Here is a similar example to what I have...
%typemap(in) double[]
{
if (!PyList_Check($input))
return NULL;
int size = PyList_Size($input);
int i = 0;
$1 = (double *) malloc((size+1)*sizeof(double));
for (i = 0; i < size; i++)
{
PyObject *o = PyList_GetItem($input,i);
if (PyNumber_Check(o))
$1[i] = PyFloat_AsDouble(o);
else
{
PyErr_SetString(PyExc_TypeError,"list must contain numbers");
free($1);
return NULL;
}
}
$1[i] = 0;
}
%include "Array.h"
%extend Array
{
Array(double lst[])
{
Array *a = new Array();
...
/* do stuff with lst[] */
...
return a;
}
}
I know the typemap is working correctly (I wrote a small test function that just prints out elements in the double[]).
I attempted putting the typemap inside the extend clause, but that did not solve the problem.
Maybe there is another way to use Python Lists inside of the extend, but I could not find any examples.
Thanks for the help in advance.
You're really close: instead of a double lst[], extend with std::list<double>:
%include "std_list.i" // or std_vector.i
%include "Array.h"
%extend Array
{
Array(const std::list<double>& numbers) {
Array* arr = new Array;
...put numbers list items in "arr", then
return a; // interpreter will take ownership
}
}
SWIG should automatically convert the Python list to the std::list.

Python C API: Parse args of string and integer in C

Refering to http://mail.python.org/pipermail/python-dev/2009-June/090210.html
AND http://dan.iel.fm/posts/python-c-extensions/
and here is other places i searched regarding my question:
http://article.gmane.org/gmane.comp.python.general/424736
http://joyrex.spc.uchicago.edu/bookshelves/python/cookbook/pythoncook-CHP-16-SECT-3.html
http://docs.python.org/2/c-api/sequence.html#PySequence_Check
Python extension module with variable number of arguments
I am inexperienced in Python/C API.
I have the following code:
sm_int_list = (1,20,3)
c_int_array = (ctypes.c_int * len(sm_int_list))(*sm_int_list)
sm_str_tuple = ('some','text', 'here')
On the C extension side, i have done something like this:
static PyObject* stuff_here(PyObject *self, PyObject *args)
{
char* input;
int *i1, *i2;
char *s1, *s2;
// args = (('some','text', 'here'), [1,20,3], ('some','text', 'here'), [1,20,3])
**PyArg_ParseTuple(args, "(s#:):#(i:)#(s#:):#(i:)#", &s1, &i1, &s2, &i2)**;
/*stuff*/
}
such that:
stuff.here(('some','text', 'here'), [1,20,3], ('some','text', 'here'), [1,20,3])
returns data in the same form as args after some computation.
I would like to know the PyArg_ParseTuple expression, is it the proper way to parse
an array of varying string
an array of integers
UPDATE NEW
Is this the correct way?:
static PyObject* stuff_here(PyObject *self, PyObject *args)
unsigned int tint[], cint[];
ttotal=0, ctotal=0;
char *tstr, *cstr;
int *t_counts, *c_counts;
Py_ssize_t size;
PyObject *t_str1, *t_int1, *c_str2, *c_int2; //the C var that takes in the py variable value
PyObject *tseq, cseq;
int t_seqlen=0, c_seqlen=0;
if (!PyArg_ParseTuple(args, "OOiOOi", &t_str1, &t_int1, &ttotal, &c_str2, &c_int2, &ctotal))
{
return NULL;
}
if (!PySequence_Check(tag_str1) && !PySequence_Check(cat_str2)) return NULL;
else:
{
//All things t
tseq = PySequence_Fast(t_str1, "iterable");
t_seqlen = PySequence_Fast_GET_SIZE(tseq);
t_counts = PySequence_Fast(t_int1);
//All things c
cseq = PySequence_Fast(c_str2);
c_seqlen = PySequence_Fast_GET_SIZE(cseq);
c_counts = PySequence_Fast(c_int2);
//Make c arrays of all things tag and cat
for (i=0; i<t_seqlen; i++)
{
tstr[i] = PySequence_Fast_GET_ITEM(tseq, i);
tcounts[i] = PySequence_Fast_GET_ITEM(t_counts, i);
}
for (i=0; i<c_seqlen; i++)
{
cstr[i] = PySequence_Fast_GET_ITEM(cseq, i);
ccounts[i] = PySequence_Fast_GET_ITEM(c_counts, i);
}
}
OR
PyArg_ParseTuple(args, "(s:)(i:)(s:)(i:)", &s1, &i1, &s2, &i2)
And then again while returning,
Py_BuildValue("sisi", arr_str1,arr_int1,arr_str2,arr_int2) ??
Infact if someone could in detail clarify the various PyArg_ParseTuple function that would be of great benefit. the Python C API, as i find it in the documentation, is not exactly a tutorial on things to do.
You can use PyArg_ParseTuple to parse a real tuple, that has a fixed structure. Especially the number of items in the subtuples cannot change.
As the 2.7.5 documentation says, your format "(s#:):#(i:)#(s#:):#(i:)#" is wrong since : cannot occur in nested parenthesis. The format "(sss)(iii)(sss)(iii)", along with total of 12 pointer arguments should match your arguments. Likewise for Py_BuildValue you can use the same format string (which creates 4 tuples within 1 tuple), or "(sss)[iii](sss)[iii]" if the type matters (this makes the integers to be in lists instead of tuples).

What is the proper usage of PyArg_ParseTuple

I am using what seems to be the exact usgae of PyArg_ParseTuple, yet the code is still failing to work. I am using python 2.7
This is my C code for the Python Extension I am writing:
static PyObject* tpp(PyObject* self, PyObject* args)
{
PyObject* obj;
PyObject* seq;
int i, len;
PyObject* item;
int arrayValue, temp;
if (!PyArg_ParseTuple(args, "O", &obj)){
printf("Item is not a list\n");
return NULL;
}
seq = PySequence_Fast(obj, "expected a sequence");
len = PySequence_Size(obj);
arrayValue = -5;
printf("[\n");
for (i = 0; i < len; i++) {
item = PySequence_Fast_GET_ITEM(seq, i);
// printf("%d : %d, PyArg: ", item, *item);
// PyArg_ParseTuple(item, "I", &temp);
PyObject* objectsRepresentation = PyObject_Repr(item);
const char* s = PyString_AsString(objectsRepresentation);
printf("%s\n", s);
PyObject* objType = PyObject_Type(item);
PyObject* objTypeString = PyObject_Repr(objType);
const char* sType = PyString_AsString(objTypeString);
printf("%s\n", sType);
if (PyArg_ParseTuple(item, "i", &arrayValue) != 0){
printf("%d\n", arrayValue);
printf("horray!\n");
}
}
Py_DECREF(seq);
printf("]\n");
printf("Item is a list!\n");
Py_RETURN_NONE;
}
Then I just build the extension and go to the terminal
import et
and then
et.tpp([1,2])
fails to print the line
if (PyArg_ParseTuple(item, "i", &arrayValue) != 0){
printf("%d\n", arrayValue);
printf("horray!\n");
}
I checked the type, as you can see in the code, of the elements in the list, and it prints 'int'. Yet for some reason PyArg_ParseTuple is having errors.
I need to be able to access information from lists in python to copy some data, pass it to my C code elsewhere, and then return the result to python.
Thank you so much!
The answer is to use long PyInt_AsLong(PyObject *io)
"long PyInt_AsLong(PyObject *io) Will first attempt to cast the object to a PyIntObject, if it is not already one, and then return its value. If there is an error, -1 is returned, and the caller should check PyErr_Occurred() to find out whether there was an error, or whether the value just happened to be -1."
This is from http://docs.python.org/2/c-api/int.html That is the official c python int objects documentation which has all relevant methods.
Unfortunately this returns only a long value. However, a simple cast should suffice if the expected values will be small.
PyArg_ParseTuple() is about parsing tuples only, as the name suggests. In your code, item is an int, not a tuple. In order to convert an int object to a C value, you need to use arrayValue = PyInt_AsLong(item). Note that it returns a C long, not an int, so you should declare arrayValue as a long.
(EDIT: previously I mentioned PyInt_FromLong by mistake.)

Overloading embedded Python functions using PyArg_ParseTuple

If I'm trying to overload an embedded Python function so that the second argument can be a long or an Object, is there a standard way to do it? Is this it?
What I'm trying now (names changed to protect the innocent):
bool UseLongVar2 = true;
if (!PyArg_ParseTuple(args, "ll:foo", &LongVar1, &LongVar2))
{
PyErr_Clear();
if (!PyArg_ParseTuple(args, "lO&:foo", &LongVar1, convertObject, &Object))
{
UseLongVar2 = false;
return NULL;
}
}
What I normally do is have two C functions that take the different arguments. The "python-facing" function's job is to parse out the arguments, call the appropriate C function, and build the return value if any.
This is pretty common when, for example, you want to allow both byte and Unicode strings.
Here is an example of what I mean.
// Silly example: get the length of a string, supporting Unicode and byte strings
static PyObject* getlen_py(PyObject *self, PyObject *args)
{
// Unpack our argument (error handling omitted...)
PyObject *arg = NULL;
PyArg_UnpackTuple(args, "getlen", 1, 1, arg) ;
if ( PyUnicode_Check(arg) )
{
// It's a Unicode string
return PyInt_FromLong(getlen_w(PyUnicode_AS_UNICODE(arg))) ;
}
else
{
// It's a byte string
return PyInt_FromLong(getlen_a(PyString_AS_STRING(arg))) ;
}
}

Is there an easy way to convert an std::list<double> to a Python list?

I'm writing a little Python extension in C/C++, and I've got a function like this:
void set_parameters(int first_param, std::list<double> param_list)
{
//do stuff
}
I'd like to be able to call it from Python like this:
set_parameters(f_param, [1.0, 0.5, 2.1])
Is there a reasonably easy way to make that conversion? Ideally, I'd like a way that doesn't need a whole lot of extra dependencies, but some things just aren't possible without extra stuff, so that's not as big a deal.
Take a look at Boost.Python. Question you've asked is covered in Iterators chapter of the tutorial
The point is, Boost.Python provides stl_input_iterator template that converts Python's iterable to stl's input_iterator, which can be used to fill your std::list.
It turned out to be less pain than I thought, once I found the docs that I probably should have read before I asked the question. I was able to get a PyList object in my wrapper function, then just iterate over it and push the values onto the vector I needed. The code looks like this:
static PyObject* py_set_perlin_parameters(PyObject* self, PyObject* args)
{
int octaves;
double persistence;
PyObject* zoom_list;
int zoom_count = 0;
std::vector<double> zoom_vector;
if(!PyArg_ParseTuple(args, "idO!:set_perlin_parameters", &octaves, &persistence, &PyList_Type, &zoom_list))
{
return NULL;
}
if(!PyList_Check(zoom_list))
{
PyErr_SetString(PyExc_TypeError, "set_perlin_parameters: third parameter must be a list");
return NULL;
}
zoom_count = PyList_Size(zoom_list);
for(int i = 0; i < zoom_count; i++)
{
PyObject* list_val;
double val;
list_val = PyList_GetItem(zoom_list, i);
if(list_val == NULL)
{
return NULL;
}
val = PyFloat_AsDouble(list_val);
zoom_vector.push_back(val);
}
set_perlin_parameters(octaves, persistence, zoom_vector);
return Py_None;
}

Categories

Resources