2012-09-03 28 views
8

Matris hesaplaması için bazı işlevleri yazmak için Cpy numpy kullanıyorum. Bugün, işlevlerimin bazı bölümlerini ayrı bir .c dosyasına taşımak ve bunları bildirmek için bir başlık kullanmak istedim. Şimdi numpy'nin import_array işleviyle ilgili garip bir problemim var. Sorunu olabildiğince basitleştirmeyi denedim. İlk başta çalışma programı vardır:Numpy C API: Bazı nesne dosyalarını bağla

mytest.c

#include "mytest.h" 

PyObject* my_sub_function() { 
    npy_intp dims[2] = {2, 2}; 
    double data[] = {0.1, 0.2, 0.3, 0.4}; 

    PyArrayObject* matrix = (PyArrayObject*)PyArray_SimpleNew(2, dims, NPY_FLOAT64); 
    memcpy(PyArray_DATA(matrix), data, sizeof(double) * dims[0] * dims[1]); 

    return (PyObject*)matrix; 
} 

static PyObject* my_test_function(PyObject* self, PyObject* args) { 
    return my_sub_function(); 
} 

static PyMethodDef methods[] = { 
    {"my_test_function", my_test_function, METH_VARARGS, ""}, 
    {0, 0, 0, 0} 
}; 

static struct PyModuleDef module = { 
    PyModuleDef_HEAD_INIT, "mytest", 0, -1, methods 
}; 

PyMODINIT_FUNC PyInit_mytest() { 
    import_array(); 
    return PyModule_Create(&module); 
} 

mytest.h

#ifndef mytest_h 
#define mytest_h 

#include <Python.h> 
#include <numpy/arrayobject.h> 
#include <numpy/npy_common.h> 

PyObject* my_sub_function(); 

#endif 

Makefile

all: mytest.o sub.o 
    gcc -shared -Wl,-soname,mytest.so -o mytest.so mytest.o 

mytest.o: sub.o 
    gcc -fPIC -c mytest.c `pkg-config --cflags python3` 

clean: 
    rm -rf *.so 
    rm -rf *.o 

Her şey beklendiği gibi çalışır. Ben make arayıp sonra modülü yüklemek ve çağrı fonksiyonu olabilir:

test.py

import mytest 
print(mytest.my_test_function()) 

ben init işlevinden import_array kaldırmak istiyorsanız davranıştır bir segfault, olacağını birçok posta listesinde ve forumda bildirilmiştir.

Şimdi sadece mytest.c kadar tüm fonksiyonlarını my_sub_function kaldırıp sub.c adlı bir dosya içine taşımak istiyorum:

#include "mytest.h" 

PyObject* my_sub_function() { 
    npy_intp dims[2] = {2, 2}; 
    double data[] = {0.1, 0.2, 0.3, 0.4}; 

    PyArrayObject* matrix = (PyArrayObject*)PyArray_SimpleNew(2, dims, NPY_FLOAT64); 
    memcpy(PyArray_DATA(matrix), data, sizeof(double) * dims[0] * dims[1]); 

    return (PyObject*)matrix; 
} 

yeni Makefile geçerli:

all: mytest.o sub.o 
    gcc -shared -Wl,-soname,mytest.so -o mytest.so mytest.o sub.o 

mytest.o: 
    gcc -fPIC -c mytest.c `pkg-config --cflags python3` 

sub.o: 
    gcc -fPIC -c sub.c `pkg-config --cflags python3` 

clean: 
    rm -rf *.so 
    rm -rf *.o 

Modülü yüklemeye ve şimdi işlevi çağırmaya çalışırsam, işlev çağrısı bana bir segfault verir. import_array numaralı telefona my_sub_function'un üstüne bir çağrı koyarsam sorunu çözebilirim, ancak bunun işlevinin kullanılması gerektiği anlamına gelmiyor.

Bunun nedenini ve numpy modülünü birkaç kaynak dosyaya bölmenin "temiz" yolunun ne olduğunu bilmek isterim.

cevap

8

Varsayılan olarak import_array rutini yalnızca NumPy C API'sini tek bir dosyada kullanılabilir duruma getirecektir. Bunun nedeni, statik bir global değişkende saklanan (yani dışa aktarılmayan ve yalnızca aynı dosya içinde görülebilen) bir işlev işaretçisi tablosu aracılığıyla çalışır. Senin uzantısı için tüm dosyalarda

  1. diğer uzantıları ile çakışabilir olası değildir eşsiz değişkene PY_ARRAY_UNIQUE_SYMBOL tanımlayın:

    mentioned in the documentation olarak, birkaç önişlemci tanımlarla bu davranışı değiştirebilir. Uzantınızın modül adını değişken ismine dahil etmek iyi bir fikir olurdu.Onları etkili olması için sırayla arrayobject.h dahil önce import_array çağrı hariç diğer tüm dosyada

  2. , NO_IMPORT_ARRAY

Bu semboller tanımlanması gerekir sembolü tanımlar.