2016-05-18 10 views
0

Ich möchte einige Ctypes-Code konvertieren, um stattdessen Cython verwenden, aber ich habe Probleme. Wesentlichen die ctypes Code:Convert Ctypes-Code in Cython

  • kopiert den Inhalt (Floats) von zwei Listen in C-kompatibel structs
  • die structs meiner binären über FFI zurück, um die structs
  • empfängt sendet (die Länge ist nie modifiziert)
  • Kopien der Inhalt in zwei neuen Listen
  • die structs zurück über die Grenze FFI sendet so ihre Speicher freigegeben werden kann

Mein ctypes Code sieht wie folgt aus bisher:

rlib.h

#ifndef RLIB_H 
#define RLIB_H 

typedef struct _FFIArray { 
    void* data; 
    size_t len; 
} _FFIArray; 

typedef struct _Result_Tuple { 
    _FFIArray e; 
    _FFIArray n; 
} _Result_Tuple; 

_Result_Tuple convert_to_bng_threaded(_FFIArray x, _FFIArray y); 
void drop_float_array(_FFIArray x, _FFIArray y) 

#endif 

mylib.pxd

cdef extern from "rlib.h": 
    struct _FFIArray: 
     void* data 
     size_t len 

    struct _Result_Tuple: 
     _FFIArray e 
     _FFIArray n 

    cdef _Result_Tuple convert_to_bng_threaded(_FFIArray x, _FFIArray y) 
    cdef void drop_float_array(_FFIArray x, _FFIArray y) 

util_cython.pyx

import cython 
from mylib cimport _FFIArray, convert_to_bng_threaded, drop_float_array 

def call_convert_bng(_FFIArray x, _FFIArray y): 
    return convert_to_bng_threaded(x, y) 

def call_drop_float_array(_FFIArray x, _FFIArray y): 
    return drop_float_array(x, y) 

setup.py

from setuptools import setup, Extension, find_packages 

from Cython.Build import cythonize 
from Cython.Distutils import build_ext 

ext = Extension('util_cython', 
      sources=['util_cython.pyx'], 
      libraries=['latlon_bng',], 
      library_dirs=['.',], 
      include_dirs=['.'] 
) 

extensions = [ext,] 

setup(
    name = "util_cython", 
    ext_modules = cythonize(extensions), 
    cmdclass={'build_ext': build_ext}, 
) 

Ich habe ein paar Fragen darüber, wie es weitergeht:

Zunächst wird die Kompilierung Schritt zur Zeit versagt:

python setup.py build_ext --inplace 
Compiling util_cython.pyx because it changed. 
[1/1] Cythonizing util_cython.pyx 

Error compiling Cython file: 
------------------------------------------------------------ 
... 
import cython 
from mylib cimport _FFIArray, convert_to_bng_threaded, drop_float_array 

def call_convert_bng(_FFIArray x, _FFIArray y): 
    return convert_to_bng_threaded(x, y) 
           ^
------------------------------------------------------------ 

util_cython.pyx:5:34: Cannot convert '_Result_Tuple' to Python object 
Traceback (most recent call last): 
    File "setup.py", line 17, in <module> 
    ext_modules = cythonize(extensions), 
    File "/Users/sth/dev/cythonize_test/venv/lib/python2.7/site-packages/Cython/Build/Dependencies.py", line 912, in cythonize 
    cythonize_one(*args) 
    File "/Users/sth/dev/cythonize_test/venv/lib/python2.7/site-packages/Cython/Build/Dependencies.py", line 1034, in cythonize_one 
    raise CompileError(None, pyx_file) 
Cython.Compiler.Errors.CompileError: util_cython.pyx 

Warum ist Cython andernfalls _Result_tuple zu konvertieren?

Zweitens: Wie definiere ich eine cython Funktionslisten zu übernehmen (oder Arrays; alles, was __iter__ unterstützt), und kopieren Sie ihren Inhalt in _FFIArray structs, so kann ich call_convert_bng nennen?

+0

Was erwarten Sie hier? Ich wäre überrascht, wenn Cython implizit ein Python-Tupel aus Ihrer benutzerdefinierten Struktur machen würde. – cel

+0

@cel Ich erwarte von jemandem, mir zu sagen, wie ich explizit darüber sprechen soll, was ich tun muss, damit Cython mein Ergebnis konvertiert? – urschrei

+0

das kann jedoch helfen: https://docs.python.org/2/c-api/tuple.html – cel

Antwort

1

Das folgende ist ungetestet, weil ich nicht den Bibliothekscode habe und einige Vermutungen nehmen musste, wie es funktioniert. Aber es sollte dir eine Idee geben, wie du das anstellst.

Ich würde mit einem Python-Array-Typ beginnen, um Ihre Eingabe/Ausgabe zu speichern. Entweder die standard library array type oder numpy Arrays. Diese speichern die Arrays kontinuierlich im Speicher (wie C würde) und so vorausgesetzt, dass das _FFIArraydata Attribut auf diesen Speicher zur Eingabe gerichtet werden kann.

def convert_bng(double[::1] x, double[::1] y): 
    # I'm assuming that the data is double, not float, but it's easy changed 
    # here the [::1] promises it's continuous in memory 
    cdef _FFIArray x_ffi, y_ffi 
    # get a pointer to the data, and cast it to void* 
    x_ffi.data = <void*>&x[0] 
    x_ffi.len = x.shape[0] # possibly *sizeof(double) - depends on the C api 

    # repeat for y 
    y_ffi.data = <void*>&y[0] 
    y_ffi.len = y.shape[0] 

    cdef _Result_Tuple result = convert_to_bng_threaded(x_ffi, y_ffi) 

    # get data pointers for the two result arrays 
    cdef double* e_ptr = <double*>(result.e.data) 
    cdef double* n_ptr = <double*>(result.n.data) 
    # now view your output arrays using memoryviews 
    # you need to tell it the length (this is how many doubles the contain) 
    cdef double[::1] e = <double[:result.e.len:1]>e_ptr 
    cdef double[::1] n = <double[:result.n.len:1]>n_ptr 

    # create a numpy copy of the two arrays 
    import numpy as np 
    e_numpy = np.copy(e) 
    n_numpy = np.copy(n) 

    # you can now free your two returned arrays 
    # I assume this is done with drop_float_array 
    drop_float_array(result.e,result.n) 

    # return as tuple containing two arrays to python 
    return e_numpy, n_numpy 
+0

Dies funktionierte einwandfrei. Vielen Dank! – urschrei