通过Cython(回调)将Python函数应用于std :: vector

Gre*_*kel 5 c++ python callback cython stdvector

我试图通过Cython学习如何在C和Python之间使用回调,并一直在看这个演示.我想将一个Python函数应用于一个std :: vector/numpy.array并将结果存储在另一个中.我可以编译并运行没有错误,但最终矢量y没有被更改.

C++标题

// callback.hpp
#include<vector> 
typedef double (*Callback)( void *apply, double &x );
void function( Callback callback, void *apply, vector<double> &x, 
               vector<double> &y );
Run Code Online (Sandbox Code Playgroud)

C++源码

// callback.cpp
#include "callback.hpp"
#include <iostream>
using namespace std;

void function( Callback callback,  void* apply,
               vector<double> &x,  vector<double> &y ) {

int n = x.size();

for(int i=0;i<n;++i) {
    y[i] = callback(apply,x[i]);
    std::cout << y[i] << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

Cython标题

# cy_callback.pxd
import cython
from libcpp.vector cimport vector

cdef extern from "callback.hpp":
     ctypedef double (*Callback)( void *apply, double &x )
void function( Callback callback, void* apply, vector[double] &x,
               vector[double] &y )
Run Code Online (Sandbox Code Playgroud)

Cython源码

# cy_callback.pyx
from cy_callback cimport function
from libcpp.vector cimport vector

def pyfun(f,x,y):
    function( cb, <void*> f, <vector[double]&> x, <vector[double]&> y )

cdef double cb(void* f, double &x):
    return (<object>f)(x)
Run Code Online (Sandbox Code Playgroud)

我用相当的样板设置编译:python setup.py build_ext -i

# setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy
import os
os.environ["CC"] = "g++"
os.environ["CXX"] = "g++"
setup( name = 'callback',
ext_modules=[Extension("callback",
             sources=["cy_callback.pyx","callback.cpp"],
             language="c++",
             include_dirs=[numpy.get_include()])],
cmdclass = {'build_ext': build_ext},
) 
Run Code Online (Sandbox Code Playgroud)

最后使用Python脚本进行测试

# test.py
import numpy as np
from callback import pyfun

x = np.arange(11)
y = np.zeros(11)
pyfun(lambda x:x**2,x,y)
print(y)
Run Code Online (Sandbox Code Playgroud)

当y的元素在callback.cpp中设置时,正确的值将被打印到屏幕上,这意味着pyfun确实正在被正确评估,但是,在Python级别,y仍然全为零.

知道我做错了什么吗?

Gre*_*kel 6

谢谢,伊恩。根据您的建议,我更改了代码以返回向量,而不是尝试就地修改它。这是有效的,虽然公认不是特别有效

回调.hpp

 typedef double (*Callback)( void *apply, double x );

 vector<double> function( Callback callback, void *apply,
                          const vector<double> &x );
Run Code Online (Sandbox Code Playgroud)

回调.cpp

vector<double> function( Callback callback, void* apply, 
                     const vector<double> &x ) {

    int n = x.size();
    vector<double> y(n);

    for(int i=0;i<n;++i) {
        y[i] = callback(apply,x[i]);
    }
    return y;
}
Run Code Online (Sandbox Code Playgroud)

cy_callback.pxd

cdef extern from "callback.hpp":
    ctypedef double (*Callback)( void *apply, const double &x )

vector[double] function( Callback callback, void* apply, 
                         vector[double] &x )
Run Code Online (Sandbox Code Playgroud)

cy_callback.pyx

from cy_callback cimport function
from libcpp.vector cimport vector

def pyfun(f,x):
    return function( cb, <void*> f, <const vector[double]&> x )


cdef double cb(void* f, double x ):
    return (<object>f)(x)
Run Code Online (Sandbox Code Playgroud)

测试文件

import numpy as np
from callback import pyfun

x = np.arange(11)
y = np.zeros(11)

def f(x):
    return x*x  

y = pyfun(f,x)
print(y)
Run Code Online (Sandbox Code Playgroud)


Ian*_*anH 1

当您将数组转换为向量时,会生成该数组的隐式副本。目前没有任何方法可以让向量获得已分配内存的所有权,因此唯一的解决方法是手动复制值或暴露std::copy给 cython。请参阅如何廉价地将 C 样式数组分配给 std::vector?