快速转换C/C++;向量到Numpy数组 我使用Sigg将一些C++代码粘到Python(2.6),其中一部分包含一段代码,将大量的数据字段(数百万个值)从C++侧转换为一个NUMPY数组。我能想到的最好的方法是为类实现一个迭代器,然后提供一个Python方法: def __array__(self, dtype=float): return np.fromiter(self, dtype, self.size())

快速转换C/C++;向量到Numpy数组 我使用Sigg将一些C++代码粘到Python(2.6),其中一部分包含一段代码,将大量的数据字段(数百万个值)从C++侧转换为一个NUMPY数组。我能想到的最好的方法是为类实现一个迭代器,然后提供一个Python方法: def __array__(self, dtype=float): return np.fromiter(self, dtype, self.size()),c++,python,arrays,numpy,swig,C++,Python,Arrays,Numpy,Swig,问题是,每个迭代器下一个调用的成本非常高,因为它必须经过三到四个SWIG包装器。时间太长了。我可以保证C++数据是连续存储的(因为它们是以STD::vector)存储的,而且它感觉就像NUMPY应该能够在它包含的值的数量上直接获取数据的指针,并且直接读取它。 有没有一种方法可以将指向internal\u data\u0]的指针和值internal\u data\u0.size()传递给numpy,这样它就可以直接访问或复制数据,而无需所有Python开销?您需要定义。这将允许您直接传回指针和形状

问题是,每个迭代器
下一个
调用的成本非常高,因为它必须经过三到四个SWIG包装器。时间太长了。我可以保证C++数据是连续存储的(因为它们是以STD::vector)存储的,而且它感觉就像NUMPY应该能够在它包含的值的数量上直接获取数据的指针,并且直接读取它。

有没有一种方法可以将指向
internal\u data\u0]
的指针和值
internal\u data\u0.size()
传递给numpy,这样它就可以直接访问或复制数据,而无需所有Python开销?

您需要定义。这将允许您直接传回指针和形状信息。

如果将向量包装在实现python的对象中,则可以将其传递给numpy数组进行初始化(请参见第三个参数)。我敢打赌,这个初始化要快得多,因为它可以使用
memcpy
来复制数据。

也许可以使用f2py而不是swig。尽管名称不同,它还是能够将python与C以及Fortran连接起来。看

优点是它可以自动处理到numpy数组的转换


两个警告:如果你还不懂Fortran,你可能会发现f2py有点奇怪;我不知道它在C++中有多好。因此,唯一的真正解决方案是将一些东西放在代码> > PyPuff.I < /C> >,它可以从C++复制到现有的缓冲区中。如果将其添加到SWIG包含文件:

%insert("python") %{
import numpy as np
%}

/*! Templated function to copy contents of a container to an allocated memory
 * buffer
 */
%inline %{
//==== ADDED BY numpy.i
#include <algorithm>

template < typename Container_T >
void copy_to_buffer(
        const Container_T& field,
        typename Container_T::value_type* buffer,
        typename Container_T::size_type length
        )
{
//    ValidateUserInput( length == field.size(),
//            "Destination buffer is the wrong size" );
    // put your own assertion here or BAD THINGS CAN HAPPEN

    if (length == field.size()) {
        std::copy( field.begin(), field.end(), buffer );
    }
}
//====

%}

%define TYPEMAP_COPY_TO_BUFFER(CLASS...)
%typemap(in) (CLASS::value_type* buffer, CLASS::size_type length)
(int res = 0, Py_ssize_t size_ = 0, void *buffer_ = 0) {

    res = PyObject_AsWriteBuffer($input, &buffer_, &size_);
    if ( res < 0 ) {
        PyErr_Clear();
        %argument_fail(res, "(CLASS::value_type*, CLASS::size_type length)",
                $symname, $argnum);
    }
    $1 = ($1_ltype) buffer_;
    $2 = ($2_ltype) (size_/sizeof($*1_type));
}
%enddef


%define ADD_NUMPY_ARRAY_INTERFACE(PYVALUE, PYCLASS, CLASS...)

TYPEMAP_COPY_TO_BUFFER(CLASS)

%template(_copy_to_buffer_ ## PYCLASS) copy_to_buffer< CLASS >;

%extend CLASS {
%insert("python") %{
def __array__(self):
    """Enable access to this data as a numpy array"""
    a = np.ndarray( shape=( len(self), ), dtype=PYVALUE )
    _copy_to_buffer_ ## PYCLASS(self, a)
    return a
%}
}

%enddef
<>这只包含一个Python C++翻译调用的开销,而不是由一个典型的长度为n的数组所导致的N。
此代码的更完整版本是my的一部分。

能否提供更详细的实际实现?还有没有一种方法可以不必根据Numpy头文件编译我的项目?谢谢。它还说这是一个遗留接口。
\uuuuu数组\uuuu接口\uuuuu
只是一个普通的dict,里面有普通类型。无需使用任何Numpy头进行编译。忽略称之为“遗留”的注释。我以为我已经删除了。如果您愿意,您可以实现PEP3118缓冲区接口,但这更容易。谢谢您的提示。您有没有使用SWIG中的
pybuffer\u mutable\u binary
或其他接口来实现float等的
\u buffer\u
接口的例子?@Seth:对不起,我不能帮您。所以看起来我必须从头开始手工实现这个类的整个缓冲接口。SWIG只提供读取其他缓冲区的功能,不导出缓冲区函数。感谢您的响应。我知道一些FORTRAN,但是我在代码中使用了很多代码> C++ +<代码> -Y特性:模板、Type Debug等。我也不想引入另一个依赖关系。C++足够公平。您可能需要编写中间的纯C包装,这可能是一件痛苦的事情。另一方面,它实际上不是另一个依赖项,因为f2py是numpy的一部分,您已经在使用它了。您不需要fortran编译器。
%template(DumbVectorFloat) DumbVector<double>;
ADD_NUMPY_ARRAY_INTERFACE(float, DumbVectorFloat, DumbVector<double>);
# dvf is an instance of DumbVectorFloat
import numpy as np
my_numpy_array = np.asarray( dvf )