从numpy C API读取许多值

从numpy C API读取许多值,numpy,python-c-api,Numpy,Python C Api,我正在尝试使用C API从一个大型numpy数组中读取许多值(按顺序)。我想要一种比在每个值上单独使用boost::python::extract(…)更有效的方法。类似于获取指向第一个值的指针,然后增加该指针 我已经通读了numpy API文档,我可以看到这是可能的,但对于如何真正实现这一点,我一点也不知道。有人能给我举个例子吗?Boost::Python API不允许您直接这样做。您可以使用Numpy C API来实现这一点。可以使用boost::python::object的ptr()方法

我正在尝试使用C API从一个大型numpy数组中读取许多值(按顺序)。我想要一种比在每个值上单独使用boost::python::extract(…)更有效的方法。类似于获取指向第一个值的指针,然后增加该指针


我已经通读了numpy API文档,我可以看到这是可能的,但对于如何真正实现这一点,我一点也不知道。有人能给我举个例子吗?

Boost::Python API不允许您直接这样做。您可以使用Numpy C API来实现这一点。可以使用
boost::python::object
ptr()
方法访问底层的
PyObject*
。可以使用
PyArray\u数据(PyObject*)
访问数据

下面是一个将2d Numpy数组乘以一个数字的示例。我发现如何在Mac OS上编译它(即Numpy头所在的位置)有些困难,所以我将在这里添加这个:running

import numpy; print numpy.get_include()
在Python中,提供了正确的包含路径。例如,您可以在cmakefind模块中使用它(例如,请参见;您必须自己设置
PYTHON\u EXECUTABLE
变量)

更新:我修改了代码以处理输入数组不连续的情况——例如,每当您使用切片时,就会发生这种情况,如
arr[::2,::2]
。处理这个问题最简单的方法是使用来自OTF的
PyArray\u
;但是,请注意,这将生成数组的副本,除非该数组已经是连续形式。这种方法的优点是,它可以处理输入是任何类型的嵌套序列(例如列表列表)的情况

如果您的数组太大,希望避免复制它,则可以使用
PyArray\u strips
获取有助于访问数据的跨距信息。从

数组
a
中元素
(i[0],i[1],…,i[n])
的字节偏移量为:

offset=sum(np.数组(i)*a.步长)

(请注意,这是字节偏移量,因此在转换为最终数据类型之前,应将其添加到
PyArray_BYTES
的结果中;此外,如果数组对齐不正确或字节顺序错误,这也不会有帮助)

以下是示例代码:

#include <boost/python.hpp>

#include <exception>

#include <numpy/arrayobject.h>

using namespace boost::python;

struct WrongSizeError : public std::exception {
  const char* what() const throw() { return "Unsupported array size."; }
};

struct WrongTypeError : public std::exception {
  const char* what() const throw() { return "Unsupported array type."; }
};

// Boost::Python needs the translators
void translate_sz(const WrongSizeError& e)
{
  PyErr_SetString(PyExc_RuntimeError, e.what());
}

void translate_ty(const WrongTypeError& e)
{
  PyErr_SetString(PyExc_RuntimeError, e.what());
}

// multiply matrix of double (m) by f
object multiply(numeric::array m, double f)
{
  PyObject* m_obj = PyArray_FROM_OTF(m.ptr(), NPY_DOUBLE, NPY_IN_ARRAY);
  if (!m_obj)
    throw WrongTypeError();

  // to avoid memory leaks, let a Boost::Python object manage the array
  object temp(handle<>(m_obj));

  // check that m is a matrix of doubles
  int k = PyArray_NDIM(m_obj);
  if (k != 2)
    throw WrongSizeError();

  // get direct access to the array data
  const double* data = static_cast<const double*>(PyArray_DATA(m_obj));

  // make the output array, and get access to its data
  PyObject* res = PyArray_SimpleNew(2, PyArray_DIMS(m_obj), NPY_DOUBLE);
  double* res_data = static_cast<double*>(PyArray_DATA(res));

  const unsigned size = PyArray_SIZE(m_obj); // number of elements in array
  for (unsigned i = 0; i < size; ++i)
    res_data[i] = f*data[i];

  return object(handle<>(res)); // go back to using Boost::Python constructs
}

BOOST_PYTHON_MODULE(test)
{
  // register exception translators
  register_exception_translator<WrongSizeError>(&translate_sz);
  register_exception_translator<WrongTypeError>(&translate_ty);

  // tell Boost::Python under what name the array is known
  numeric::array::set_module_and_type("numpy", "ndarray");
  def("multiply", multiply);

  // initialize the Numpy C API
  import_array();
}
#包括
#包括
#包括
使用名称空间boost::python;
struct ErrorSizeError:public std::exception{
const char*what()const throw(){返回“不支持的数组大小”。;}
};
结构错误类型错误:公共标准::异常{
const char*what()const throw(){返回“不支持的数组类型”。;}
};
//Python需要转换器
void translate_sz(const errosizeerror&e)
{
PyErr_SetString(PyExc_RuntimeError,例如what());
}
无效翻译(常量错误类型错误&e)
{
PyErr_SetString(PyExc_RuntimeError,例如what());
}
//将双(m)矩阵乘以f
对象乘法(数值::数组m,双f)
{
PyObject*m_obj=PyArray_FROM_OTF(m.ptr(),NPY_DOUBLE,NPY_IN_数组);
如果(!m_obj)
抛出错误类型错误();
//为了避免内存泄漏,让Boost::Python对象管理数组
对象温度(句柄(m_obj));
//检查m是否为双精度矩阵
int k=PyArray_NDIM(m_obj);
如果(k!=2)
抛出错误的sizeError();
//直接访问阵列数据
const double*data=static_cast(PyArray_data(m_obj));
//创建输出数组,并访问其数据
PyObject*res=PyArray\u SimpleNew(2,PyArray\u DIMS(m\u obj),NPY\u DOUBLE);
double*res_data=静态_cast(PyArray_data(res));
const unsigned size=PyArray_size(m_obj);//数组中的元素数
for(无符号i=0;i
当输入数组是切片操作的结果时,如在
乘法(foo[:3],x)
中,这是否起作用?因为您只需要获取指向数据的指针,然后执行单个步骤,所以我假设当跨步不是1时,这将失败?是的,我应该提到这一点——我编写的代码只适用于连续数组。我更新了答案以提供解决方案。