如何在 C++ 头文件和源文件中使用 NumPy C-API?

2024-01-08

我正在使用 Boost::Python 将 Python 代码提供给 C++ 库。我有一个将 C++ 类型转换为 Python 类型的模板函数:

template <typename T> bp::object convert(T v);

它专门用于各种原始类型以及一些模板化类。其中一个类是 N 维数组,我有一个函数可以将其转换为 NumPy 数组。我想在相应的功能中使用这个功能convert专业化,例如:

template <typename Y> bp::object convert(NDArray<Y> v);

我的主要问题是这个转换函数需要存在于标头中,因为它是模板化的,但它使用 NumPy 的PyArray_函数,这需要import_array()在使用之前调用。import_array()当前在单例对象的构造函数中调用,其目的是提供对 Python 函数的访问。看来这行不通,因为默认情况下,#include <numpy/arrayobject.h>只使得PyArray_当前编译单元可用的函数。我尝试过定义一个PY_ARRAY_UNIQUE_SYMBOL并定义NO_IMPORT_ARRAY对于标题,但这并不能阻止PyArray_防止段错误的功能。

这是我的代码的简化表示,它在使用时出现段错误PyArray_“conversions.h”标头中的函数:

“转换.h”:

#include <boost/python.hpp>
#include <numpy/numpyconfig.h>
#include <numpy/arrayobject.h>

namespace bp = boost::python;

template <typename T> bp::object convert(T v);
template <> bp::object convert<int>(int v) { return bp::long_(v); }
...
template <typename Y> bp::object convert(NDArray<Y> v)
{
... use PyArray_ functions to create and return a NumPy array
... segfaults here!
}

“桥.h”:

#include "conversions.h"

class Bridge {
public:
    static Bridge* instance();

    // c++11 variadic template (parameter pack)
    template <typename... Args> void exec(Args... args)
    {
        ...
        fn(convert(args)...); // fn is a Python function
        ...
    }
    void foo();

private:
    Bridge();
    Bridge(const Bridge&);
    void operator=(const Bridge&);
    static Bridge* instance_;
}

“桥.cpp”:

#include "Bridge.h"
#include <numpy/numpyconfig.h>
#include <numpy/arrayobject.h>

Bridge* Bridge::instance_ = nullptr;
Bridge* Bridge::instance() {
    if (!instance_) { instance_ = new Bridge(); }
    return instance_;
}
Bridge::Bridge() {
    Py_Initialize();
    _import_array();
    ...
}
void Bridge::foo() {
    ... // other stuff using PyArray functions
}

“主.cpp”:

#include "Bridge.h"

int main(void)
{
    NDArray my_array(...);
    Bridge::instance()->exec(42, "hello", my_array); 
    return 0;
}

我后来了解到一个问题是对 PyArray 函数的调用应该与对 PyArray 函数的调用发生在同一编译单元中import_array(NumPy 初始化函数)。

解决这个问题的一种方法是“包装”PyArray_*内部函数并使用它们而不是直接使用 NumPy API。

可能找到了另一种解决方案here http://docs.scipy.org/doc/numpy-1.10.1/user/c-info.how-to-extend.html#required-subroutine.

我的解决方案:

创建一个“numpy_wrappers.h”文件:

...
#include "numpy/ndarraytypes.h"

int NumPyArray_NDIM(PyObject* obj);
npy_intp NumPyArray_DIM(PyObject* obj, int i);
void *NumPyArray_DATA(PyObject* obj);
...

然后通过将原始函数“包装”来实现这些与您的调用相同的源文件 import_array(NumPy初始化函数):

...
Bridge::Bridge() {
    Py_Initialize();
    _import_array();
    ...
}
...
/// Wraps PyArray_NDIM
int NumPyArray_NDIM(PyObject* obj)
{
    return PyArray_NDIM((PyArrayObject*)obj);
}

/// Wraps PyArray_DIM
npy_intp NumPyArray_DIM(PyObject* obj, int i)
{
    return PyArray_DIM((PyArrayObject*)obj, i);
}

/// Wraps PyArray_DATA
void* NumPyArray_DATA(PyObject* obj)
{
    return PyArray_DATA((PyArrayObject*)obj);
}
...

然后它们可以在模板标题中使用,如下所示:

...
template <typename Y> bp::object convert(NDArray<Y> v)
{
... use NumPyArray_ functions to create and return a NumPy array
... No more segfaults!
}
...

你可以看到这个的深入实现here https://github.com/gadgetron/gadgetron/tree/master/toolboxes/python,一个用于在一些 C++ STL 类型和 Python 标准类型之间无缝转换的工具箱。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 C++ 头文件和源文件中使用 NumPy C-API? 的相关文章

  • 是否有可能将 *.pdb 文件包含到发布版本中以查看错误行号?

    我做了一个项目 所有设置都是默认的 当我在调试模式 构建配置 调试 下运行它并遇到异常时 它转储到我的自定义日志记录机制 其中包含错误行号 但是当我运行发布构建时 记录相同的异常 没有行号 只有方法抛出和记录调用堆栈 是否有可能在发布配置
  • 使用 GCHandle 将大型结构数组从 C# unity 脚本传递到 C++ dll 在 C++ 函数执行后崩溃

    我想从 C unity 脚本将结构数组传递给 c 本机插件 我做了如下操作 我可以访问数据 但我的应用程序在执行 c 函数后崩溃 我不知道为什么 C side StructLayout LayoutKind Sequential publi
  • std::bind2nd 和 std::bind 与二维数组和结构数组

    我知道 C 有 lambda 并且 std bind1st std bind2nd 和 std bind 已弃用 然而 从C 的基础开始 我们可以更好地理解新特性 所以 我从这个非常简单的代码开始 使用int 数组s 第一个例子 与std
  • 静态 OpenCV 库中未定义的引用

    我有一个使用 OpenCV 3 1 的 C 项目 并且使用共享库可以正常工作 但现在我想使用静态库 位于项目目录中的文件夹中 来编译它 因为我希望能够在未安装 OpenCV 的情况下导出它 如果需要还可以编辑和重新编译 这次我重新编译了 O
  • C语言中没有循环可以打印数组吗?

    例如 在Python中 如果我们将一个列表作为数组 它会直接用一行代码打印整个数组 有什么办法可以用C语言实现同样的事情吗 简短回答 No 对表格上几乎所有问题的简短回答 用 C 语言做 X 工作能像用 Python 一样简单吗 No 长答
  • c 使用 lseek 以相反顺序复制文件

    我已经知道如何从一开始就将一个文件复制到另一个文件 但是我如何修改程序以按相反的顺序复制它 源文件应具有读取访问权限 目标文件应具有读写执行权限 我必须使用文件控制库 例如 FILE A File B should be ABCDEF FE
  • C# 实体框架我们应该使用 POCO.Id 还是仅使用 POCO 设置关系?

    我在服务方法中遇到一种情况 将 POCO 分配为另一个 POCO 的子对象无法按预期工作 我正在使用实体框架 4 public void ChangeOrderCurrency Currency currency order Currenc
  • AcceptSocket 超时?

    是否有可能AcceptSocket on a TcpListener具有超时的对象 以便它偶尔被中断 TcpListener server new TcpListener localIP port server Start while sh
  • PartialView Action 正在调用自身

    我有 MVC 应用程序 它用于从主视图 ProductMaster 将 ProductAreaGrid 列表显示为 PartialView 并且它将在局部视图内将 CreateProductArea 作为 PartialView 我的 Gr
  • 根据 Active Directory 策略检查密码[重复]

    这个问题在这里已经有答案了 我有一个允许用户更改其 AD 密码的前端 有没有办法获取特定用户及其属性 长度 复杂性 的密码策略 例如细粒度 有没有办法根据此特定策略检查字符串 xyz121 编辑 我不想检查活动目录中存储的当前密码 我想检查
  • 使用 catch all 字典属性将 json 序列化为对象

    我想使用 JSON net 反序列化为对象 但将未映射的属性放入字典属性中 是否可以 例如给定 json one 1 two 2 three 3 和 C 类 public class Mapped public int One get se
  • 从二进制文件读取字节到 long int

    我有两个问题 我有二进制文件的数据 我想使用 read 函数读取前 8 个字节以签署 long int 但我不能 你知道我该怎么做吗 如何直接读取一块数据到字符串中 我可以像所示那样阅读吗 前任 ifstream is is open te
  • C# 反序列化过程中创建指向父对象的指针

    我有这样的课程 Serializable public class child public Parent parent Serializable public class Parent public List
  • 禁用实体框架的默认值生成(Code First)

    我数据库中有一个列不能为空 我想将其设置为默认值在数据库中 问题是实体框架似乎自己创建了一个默认值 例如 int gt 0 并且完全忽略了数据库中的默认值约束 有没有办法禁用实体框架的默认值 我发现您可以使用以下属性来装饰您的字段 Data
  • 如何使用 C# 将表格粘贴到 Ms-Word 文档的末尾

    我有一个预制的 Word 模板 其中有一个表格 我想打开它 然后在文档末尾添加 粘贴 另一个表格 问题是它不会转到文档的末尾 而是将新表格粘贴到原始表格的第一个单元格中 任何帮助将不胜感激 previous code copied a ta
  • 如何在 ASP.NET Core 项目中使用 MStest 测试 Ok() 结果

    我正在使用 MStest 来测试我的控制器 我想测试这个动作 HttpGet Name GetGroups public async Task
  • 如何使 WinForms UserControl 填充其容器的大小

    我正在尝试创建一个多布局主屏幕应用程序 我在顶部有一些按钮链接到应用程序的主要部分 例如模型中每个实体的管理窗口 单击这些按钮中的任何一个都会在面板中显示关联的用户控件 面板包含用户控件 而用户控件又包含用户界面 WinForms User
  • 在 lua 中加载 C++ 模块时出现“尝试索引字符串值”错误

    我正在尝试使用 lua 用 C 编写的函数 下面给出的是cpp文件 extern C include lua h include lauxlib h include lualib h static int add 5 lua State L
  • C# 模式匹配

    我对 C 有点陌生 我正在寻找一个字符串匹配模式来执行以下操作 我有一个像这样的字符串 该书将在 唐宁街 11 号接待处 并将由主要医疗保健人员参加 我需要创建一个 span 标签来使用 startIndex 和 length 突出显示一些
  • 检查另一种形式的线程是否仍在运行

    我有一个涉及两个窗体的 Windows 窗体应用程序 子表单用于将数据导出到 CSV 文件 并使用后台工作者写入文件 当这种情况发生时 我隐藏了表格 当后台工作程序运行时 父窗体仍然处于活动状态 因此即使后台工作程序正在写入文件 用户也可以

随机推荐