6

我有一个函数,它接受一个 int 指针并通过 boost::python 公开它。如何从 python 调用这个函数?

在带有 boost::python 的 C++ 中:

void foo(int* i);
...
def("foo", foo);

在蟒蛇中:

import foo_ext
i = 12
foo_ext.foo(i)

结果是

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
foo(int)
did not match C++ signature:
foo(int* i)

那么如何传递指针呢?

4

3 回答 3

4

简短的回答是:你不能。Python没有指针

长答案是:根据用例有各种解决方法。

我注意到您在示例中使用了 int 和 int* 。Int(连同 float、str 和 bool)是一种特殊情况,因为它在 python 中是不可变的。

假设您传入的对象并不是真正的 int。

有一个将参数作为引用的包装函数,获取地址并将其传递给实际函数。这将在 python 中无缝工作。


好的,所以说它确实是一个 int。现在你有问题了。您无法更改传入的 int。如果您尝试相同的解决方案,boost::python 将在运行时抱怨 l-values。仍然有几种选择。

假设您不需要在函数退出后查看 int 的样子,并且您知道该函数不会在函数返回后将指向取消引用的指针隐藏起来:

您的包装器现在应该通过值或 const 引用来获取 int。其他一切都是一样的。


也许您只需要查看 after 状态(int 是 OUT 边界):

您的包装函数现在将不接受任何参数,并将本地 int 的地址传递给实际函数。它将返回该值。如果你的函数已经有一个返回值,它现在应该返回一个元组。


输入和输出都很重要,并且您知道函数不会在函数返回后将指向取消引用的指针隐藏起来:

结合以上两种。包装器按值获取一个 int 并返回一个不同的 int。


该函数希望在函数返回后将指向取消引用的指针隐藏起来:

没有真正好的解决方案。您可以在 c++ 中创建和公开一个包含 c++ int 的对象。包装器将通过引用获取该对象,提取包含的 int 的地址并将其传递给实际函数。保持对象在 python 中的活动(并且不受垃圾收集器的影响)直到库完成它现在是 python 编写器的问题,如果他搞砸了数据已损坏或解释器崩溃。

于 2010-11-09T20:31:53.883 回答
1

来自python.org 的 boost.python HowTo

也许您希望生成的 Python 对象包含指向参数的原始指针?在这种情况下,需要注意的是,如果 C++ 对象的生命周期在 Python 对象的生命周期之前结束,则该指针将悬空,并且使用 Python 对象可能会导致崩溃。

以下是如何在模块初始化期间公开可变 C++ 对象:

scope().attr("a") = object(ptr(&class_instance));
于 2010-10-07T12:59:57.727 回答
1

大多数情况下,您可以避免将原始指针传递给函数,但是当确实需要时,您可以使用适配器以这种方式为指向原始对象的 C++ 指针创建 Python 对象:

template<typename PtrT>
struct PtrAdapter {
    auto& get(PtrT ptr)  { return *ptr; }
};

然后定义指针类型到 Python 对象的映射并允许隐式转换:

class_<Cluster<LinksT>*, noncopyable>(typpedName<LinksT>("ClusterPtr", true, true)
, "Raw hierarchy cluster pointer\n")
    .def("__call__", &PtrAdapter<Cluster<LinksT>*>::get,
        return_internal_reference<>(),
        "referenced cluster")
    ;
register_ptr_to_python<Cluster<LinksT>*>();

请注意,原始对象类型也应该映射到 Python 对象(在这种情况下Cluster<LinksT>)。

然后对于这样的 C++ 代码:

Cluster<LinksT>* cl = clusters.head();
process(cl);
Id cid = cl->id();

您可以使用类似的 Python 代码:

cl = clusters.head()
process(cl)
cid = cl.id()
于 2014-01-15T17:34:08.863 回答