【问题标题】:Apply a Python function to an std::vector via Cython (callback)通过 Cython(回调)将 Python 函数应用于 std::vector
【发布时间】:2015-02-16 21:18:09
【问题描述】:

我正在尝试通过 Cython 学习如何在 C 和 Python 之间使用回调,并且一直在关注 this demo。我想要一个 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 );

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;
}

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 )

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)

我使用相当样板的设置进行编译: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},
) 

最后用 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)

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

知道我做错了什么吗?

【问题讨论】:

    标签: python c++ callback cython stdvector


    【解决方案1】:

    谢谢,伊恩。根据您的建议,我更改了代码以返回一个向量,而不是尝试对其进行修改。这行得通,虽然诚然不是特别有效

    回调.hpp

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

    回调.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;
    }
    

    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 )
    

    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)
    

    test.py

    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)
    

    【讨论】:

      【解决方案2】:

      当您将其转换为向量时,会生成数组的隐式副本。 目前没有任何方法可以让向量拥有已分配的内存的所有权,因此唯一的解决方法是手动复制值或将 std::copy 暴露给 cython。见How to cheaply assign C-style array to std::vector?

      【讨论】:

        猜你喜欢
        • 2012-07-26
        • 2019-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多