2

我无法使用 pybind11 将全局变量从 C 导出到 Python。这个问题可以从一个简单的例子中重现。假设我们有一个像这样的头文件(global.h):

#ifndef GLOBAL_H
#define GLOBAL_H

extern int array[];

#endif 

该数组在 C 文件 (global.c) 中定义,如下所示:

#include "global.h"

int array[] = {1, 2, 3, 4};

我想使用 pybind11 和以下 C++ 文件 (pyglobal.cpp) 在 Python 模块中导出这个数组:

#include <pybind11/pybind11.h>

extern "C"
{
  #include "global.h"
}

PYBIND11_MODULE(pyglobal, m)
{
  m.attr("array") = array;
}

当我使用 CMake (CMakeLists.txt) 生成我的库时,一切正常:

cmake_minimum_required(VERSION 2.8.12)
project(pyglobal)

find_package(pybind11 PATHS ${PYBIND11_DIR} REQUIRED)

pybind11_add_module(pyglobal pyglobal.cpp global.c)

但是当我启动 python3 shell 并输入

import pyglobal

我收到以下错误消息:

> Python 3.5.2 (default, Nov 23 2017, 16:37:01) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyglobal
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: AttributeError: array

我在这里做错了什么?

4

1 回答 1

1

该分配是一个相当不幸的隐式转换,因此不会做你认为它做的事情。以下是公开该数组的一种方法,假设您安装了 numpy:

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

extern "C"
{
  #include "global.h"
}

PYBIND11_MODULE(pyglobal, m)
{
  auto dtype = pybind11::dtype(pybind11::format_descriptor<int>::format());
  m.attr("array") = pybind11::array(dtype, {3}, {sizeof(int)}, array, nullptr);
}

如果您不知道大小,您可以使用一个空的基本数组和一个大的(假的)大小。请确保不要以范围限制方式以外的任何方式迭代数组。例子:

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

extern "C"
{
  #include "global.h"
}

PYBIND11_MODULE(pyglobal, m)
{
  auto dtype = pybind11::dtype(pybind11::format_descriptor<int>::format());
  auto base = pybind11::array(dtype, {(unsigned)-1}, {sizeof(uintptr_t)});
  m.attr("array") = pybind11::array(dtype, {(unsigned)-1}, {sizeof(int)}, array, base);
}

可以这样使用:

>>> import pyglobal
>>> for i in range(3):
...     print(pyglobal.array[i])
... 
1
3
0
>>>

但例如不能打印,因为这会迭代整个(unsigned)-1尺寸。

于 2019-11-17T23:04:15.890 回答