Форум сайта python.su
Пытаюсь разобраться со списками, пока простой пример, получить длину списка:
static PyObject *sum_cmd(PyObject *self, PyListObject *mass){
Py_ssize_t n=0;
n=PyList_Size((PyObject*)mass);
return Py_BuildValue("i",n);
}
>>> import mymod
>>> mymod.sum([1,2,3,4,5])
-1
Офлайн
вот этот вариант , воообще вылетает с ошибкой сегментирования
double sum_cmd(PyObject *mass){
int i, n=0;
double x,res = 0.0;
PyObject *item;
n=PyList_Size(mass);
for(i=0;i<n;++i){
item=PyList_GetItem(mass,i);
PyArg_ParseTuple(item,"d",&x);
res+=x;
}
return res;
}
Офлайн
А вам в какую сторону работать? embedding или extending? Обычно встраивание в том или ином виде это расширение. Я делал расширения притона с помощью ctypes, Берется указатель и размерность средствами питона и подставляются в сишную функцию. Для numpy это очень эффективный способ.
a=numpy.zeros(5)
myfunction(a.ctypes.data,5)
Отредактировано (Май 29, 2011 07:28:32)
Офлайн
Давайте по порядку. Описание функции должно быть
static PyObject *sum_cmd(PyObject *self, PyObject *args);
args - это не первый аргумент, а кортеж аргументов (tuple). Потому что в таблице функций модуля было METH_VARARGS, я предполагаю.
Первый аргумент, он же список, получается через PyArg_ParseTuple(args, “i:myfunction”, &lst);
Дальше нужно взять размер списка. Для именно списка можно использовать две функции: PySequence_Size и PyList_Size.
PySequence_Size работает с любым объектом, у которого есть __len__. PyList_Size требует именно list или его потомка. Для проверки перед вызовом список нужно проверить на PyList_Check и выбросить исключение в случае чего.
PyList_Size должен быть быстрее чем PySequence_Size. На сколько — не проверял. Для каждого конкетного случая (зависящего в том числе и от типа аргумента), значения могут быть разными.
Для numpy нужно использовать http://docs.scipy.org/doc/numpy/reference/c-api.html точно так же, как и для стандартных встроенных объектов. Замените PyList_ на PyArray_ — и дело пойдет.
И, наконец, самое главное. Вседа проверяйте, что вам возвращают функции из C API. Если была ошибка — нужно ее обработать и, как правило, выбросить исключение. Иначе будете периодически получать segmentation fault. И ссылки не забывайте считать аккуратно — тоже распространенная причина проблем.
Офлайн
doza_andБуду пробовать провести два варианта. Ваш вариант обращения к функции С выглядит более простым, и обнадеживает. Нужно на С пересвести вот эту функцию:
А вам в какую сторону работать?
def matrix(bRow, bCol, out=None):
for i in range(len(bRow)):
for j in range(len(bCol)):
out[i][j]=funct(bRow[i],bCol[j])
[[[-0.240688 -0.03071 -1.119206]
[-0.366261 -0.090405 -1.130639]
[-0.320687 0.028917 -1.221789]]
[[-0.366261 -0.090405 -1.130639]
[-0.240688 -0.03071 -1.119206]
[-0.290936 -0.141951 -1.018888]]
[[-0.169737 -0.077079 -1.003905]
[-0.290936 -0.141951 -1.018888]
[-0.240688 -0.03071 -1.119206]]
...,
void matrix(const double & bRow[][][],const double & bCol[][][],double & out[][]){
// обращение к элементу bCol[i][j][k]
}
void matrix(const double & bRow[],const double & bCol[], double & out[]){
// обращение к элементу bCol[N*i+M*j+k]
}
[array([[-2.103271, 0.676978, 0.793785],
[-1.95313 , 0.676978, 0.681567],
[-1.95313 , 0.594438, 0.793785]]), array([[-1.95313 , 0.594438, 0.793785],
[-1.95313 , 0.451738, 1.193785],
[-2.35313 , 0.662126, 1.193785],
[-2.35313 , 0.676978, 1.158403]]),
...
Офлайн
Андрей СветловСпасибо, буду разбираться. Нет ли какого учебника по разработке С модулей для Питона?
Давайте по порядку.
Офлайн
а в С++ не будет ли слишком тормозными такие структуры
std::vector<std::vector<double> > out(n,std::vector<double>(n));
std::vector<std::vector<std::vector<double> > >bRow
Офлайн
Учебника, да еще и на русском — думаю, что не существует.
Дело не в том, тормозной std::vector или нет. Вопрос иной — как представлен numpy.array? Не нужно переконвертировать из этого массива туда и обратно на каждом шагу — берите то что уже есть. И определитесь, у вас С или таки С++? В данном случае есть разница. А вообще doza_and правильно пишет — если вам получится обойтись только ctypes — то так и делайте. Python C API, как и более высокоуровневые обертки, требует некоторого привыкания.
Офлайн
Андрей СветловПомогите, пожайлуста, разобраться. Вычитал что std::vector поддерживает указатели и в качестве параметра функции может быть передан простой массив. Ну, и как я понял, вызывая vect.ctypes.data мы передаем указатель на начало вектора, т.е типы в коде ниже совместимы.
Учебника, да еще и на русском — думаю, что не существует.
Дело не в том, тормозной std::vector или нет. Вопрос иной — как представлен numpy.array? Не нужно переконвертировать из этого массива туда и обратно на каждом шагу — берите то что уже есть. И определитесь, у вас С или таки С++? В данном случае есть разница. А вообще doza_and правильно пишет — если вам получится обойтись только ctypes — то так и делайте. Python C API, как и более высокоуровневые обертки, требует некоторого привыкания.
$ cat test.c
#include <vector>
extern int myfill(std::vector<double> & x){
size_t n = x.size();
for(int i=0; i<n; ++i){
x[i]=i;
}
return 0;
}
$ cat test.py
#!/usr/bin/python
import numpy as N
import ctypes as C
_foo = N.ctypeslib.load_library('test', '.')
from numpy.ctypeslib import ndpointer
#_foo.myfill.argtype=ndpointer(ndim=1)
#vect=N.zeros(5,ndpointer(ndim=1))
vect=N.zeros(10)
_foo.myfill(vect.ctypes.data)
#_foo.myfill(x.ctypes.data_as(ndpointer(ndim=1)))
print vect
$ c++ -fPIC -shared test.c -o test.so
$ ./test.py
Traceback (most recent call last):
File "./test.py", line 10, in <module>
_foo.myfill(vect.ctypes.data)
File "/usr/lib/python2.7/ctypes/__init__.py", line 366, in __getattr__
func = self.__getitem__(name)
File "/usr/lib/python2.7/ctypes/__init__.py", line 371, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: /media/disk/call-c/test/test.so: undefined symbol: myfill
Офлайн
Если вас интересует быстродействие то думаю надо начать с того где определена funct - ваша функция преобразования. Пробегание по массивам будет ерундой по сравнению с вызовами питоновской функции.
Ваше затруднение с вызовом функции не ясно - вы не привели сишную функцию (или ее декларацию).
Ваша затея имеет смысл если набор функций funct тоже откомпилированы
void cCommonTensorProduct(const double* arg1,const int* shape1,int ndim1,const double* arg2,const int* shape2,int ndim2,double* result,void (*f)(double,double))
{
int index1[10],index2[10]
level=0
beg:
for(index1[level]=0;index1[level]<shape1[level];++index1[level])
{
if(level<ndim1) {++level;goto beg;}
for(;;)
{
....
result[i]=f(arg1[i],arg2[k]);
....
}
end:;
}
if(level!=0) {--level;goto end;}
}
def CommonTensorProduct(arg1,arg2,f):
shape1=nd.array(arg1.shape,dtype='i')
shape2=nd.array(arg2.shape,dtype='i')
res=nd.zeros(arg1.shape+arg2.shape,dtype='d')
# надо еще проверить dtype для arg1,arg2 и если не подходит - преобразовать
cCommonTensorProduct(arg1.ctypes.data,shape1.ctypes.data,len(arg1.shape),arg2.ctypes.data,shape2.ctypes.data,len(arg2.shape),res.ctypes.data,f)
Отредактировано (Май 30, 2011 21:15:35)
Офлайн