将类型对象(类,而不是实例)从 python 传递到 c++

2024-01-12

我想要一个boost::python-wrappedC++ 函数能够接收类型(而不是实例)boost::python- 包装的 C++ 类。我可以声明包装的函数采用object,但是如何提取类型呢?我尝试过类似的方法,但类型对象似乎不是extract-able:

#include<boost/python.hpp>
namespace py=boost::python;

struct A {};
struct B: public A {};

int func(py::object klass) {
    py::extract<std::type_info> T(klass);
    if(!T.check()) throw std::runtime_error("Unable to extract std::type_info");
    if(T()==typeid(A)) return 0;
    if(T()==typeid(B)) return 1;
    return -1;
}

BOOST_PYTHON_MODULE(deadbeef)
{
   py::def("func",func);
   py::class_<A>("A");
   py::class_<B,py::bases<A>>("B");
}

编译为

clang++ -lboost_python -fPIC `pkg-config python --cflags` a.cc -std=c++11 -shared -o deadbeef.so

I run

PYTHONPATH=. python
>>> import deadbeef
>>> deadbeef.func(deadbeef.A)  ## I want this to return 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: Unable to extract std::type_info

感谢您的任何想法。


要传递 Python 类型对象,需要创建一个 C++ 类型并注册一个自定义转换器。由于 Python 类型对象是一个 Python 对象,因此创建一个派生自的类型boost::python::object是合适的:

/// @brief boost::python::object that refers to a type.
struct type_object: 
  public boost::python::object
{
  /// @brief If the object is a type, then refer to it.  Otherwise,
  ///        refer to the instance's type.
  explicit
  type_object(boost::python::object object):
    boost::python::object(get_type(object))
  {}

private:

  /// @brief Get a type object from the given borrowed PyObject.
  static boost::python::object get_type(boost::python::object object)
  {
    return PyType_Check(object.ptr())
      ? object 
      : object.attr("__class__");
  }
};

// ... register custom converter for type_object.

然而,示例代码提出了一个额外的问题。 Python 类型对象和 C++ 类型之间无法直接进行比较。此外,Python 类型对象与 C++ 类型没有直接关联。为了进行比较,需要比较Python类型对象。

Boost.Python 使用内部注册表来关联 C++ 类型标识,其形式为boost::python::type_info http://www.boost.org/doc/libs/release/libs/python/doc/v2/type_id.html#type_info-spec,到一个Python类对象。这种关联是单向的,因为只能查找 Python 类对象。让我们扩展一下type_object类允许提供辅助函数来检查 C++ 类型:

/// @brief boost::python::object that refers to a type.
struct type_object: 
  public boost::python::object
{
  ...

  /// @brief Type identity check.  Returns true if this is the object returned
  ///        returned from type() when passed an instance of an object created
  ///        from a C++ object with type T.
  template <typename T>
  bool is() const
  {
    // Perform an identity check that registartion for type T and type_object
    // are the same Python type object.
    return get_class_object<T>() == static_cast<void*>(ptr());
  }

  /// @brief Type identity check.  Returns true if this is the object is a
  ///        subclass of the type returned returned from type() when passed
  ///        an instance of an object created from a C++ object with type T.
  template <typename T>
  bool is_subclass() const
  {
    return PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(ptr()),
                            get_class_object<T>());
  }

private:

  ...

  /// @brief Get the Python class object for C++ type T.
  template <typename T>
  static PyTypeObject* get_class_object()
  {
    namespace python = boost::python;
    // Locate registration based on the C++ type.
    const python::converter::registration* registration =
          python::converter::registry::query(python::type_id<T>());

    // If registration exists, then return the class object.  Otherwise,
    // return NULL.
    return (registration) ? registration->get_class_object()
                          : NULL;
  }
};

Now, if type是一个实例type_object,可以检查:

  • If type是与 C++ 关联的 Python 类型Spam键入type.is<Spam>().
  • If type是与 C++ 相关的 Python 类型的子类Spam键入type.is_subclass<Spam>().

这是一个基于原始代码的完整示例展示 http://coliru.stacked-crooked.com/a/3021cdc765dee604接收类型对象到函数,检查类型标识和子类:

#include <boost/python.hpp>

/// @brief boost::python::object that refers to a type.
struct type_object: 
  public boost::python::object
{
  /// @brief If the object is a type, then refer to it.  Otherwise,
  ///        refer to the instance's type.
  explicit
  type_object(boost::python::object object):
    boost::python::object(get_type(object))
  {}

  /// @brief Type identity check.  Returns true if this is the object returned
  ///        returned from type() when passed an instance of an object created
  ///        from a C++ object with type T.
  template <typename T>
  bool is() const
  {
    // Perform an identity check that registartion for type T and type_object
    // are the same Python type object.
    return get_class_object<T>() == static_cast<void*>(ptr());
  }

  /// @brief Type identity check.  Returns true if this is the object is a
  ///        subclass of the type returned returned from type() when passed
  ///        an instance of an object created from a C++ object with type T.
  template <typename T>
  bool is_subclass() const
  {
    return PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(ptr()),
                            get_class_object<T>());
  }

private:

  /// @brief Get a type object from the given borrowed PyObject.
  static boost::python::object get_type(boost::python::object object)
  {
    return PyType_Check(object.ptr())
      ? object 
      : object.attr("__class__");
  }

  /// @brief Get the Python class object for C++ type T.
  template <typename T>
  static PyTypeObject* get_class_object()
  {
    namespace python = boost::python;
    // Locate registration based on the C++ type.
    const python::converter::registration* registration =
          python::converter::registry::query(python::type_id<T>());

    // If registration exists, then return the class object.  Otherwise,
    // return NULL.
    return (registration) ? registration->get_class_object()
                          : NULL;
  }
};

/// @brief Enable automatic conversions to type_object.
struct enable_type_object
{
  enable_type_object()
  {
    boost::python::converter::registry::push_back(
      &convertible,
      &construct,
      boost::python::type_id<type_object>());
  }

  static void* convertible(PyObject* object)
  {
    return (PyType_Check(object) || Py_TYPE(object)) ? object : NULL;
  }

  static void construct(
    PyObject* object,
    boost::python::converter::rvalue_from_python_stage1_data* data)
  {
    // Obtain a handle to the memory block that the converter has allocated
    // for the C++ type.
    namespace python = boost::python;
    typedef python::converter::rvalue_from_python_storage<type_object>
                                                                 storage_type;
    void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;

    // Construct the type object within the storage.  Object is a borrowed 
    // reference, so create a handle indicting it is borrowed for proper
    // reference counting.
    python::handle<> handle(python::borrowed(object));
    new (storage) type_object(python::object(handle));

    // Set convertible to indicate success. 
    data->convertible = storage;
  }
};

// Mockup types.
struct A {};
struct B: public A {};
struct C {};

/// Mockup function that receives an object's type.
int func(type_object type)
{
  if (type.is<A>()) return 0;
  if (type.is<B>()) return 1;
  return -1;
}

/// Mockup function that returns true if the provided object type is a
/// subclass of A.
bool isSubclassA(type_object type)
{
  return type.is_subclass<A>();
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;

  // Enable receiving type_object as arguments.
  enable_type_object();

  python::class_<A>("A");
  python::class_<B, python::bases<A> >("B");
  python::class_<C>("C");

  python::def("func", &func);
  python::def("isSubclassA", &isSubclassA);
}

互动使用:

>>> import example
>>> assert(example.func(type("test")) == -1)
>>> assert(example.func(example.A) == 0)
>>> assert(example.func(example.B) == 1)
>>> assert(example.isSubclassA(example.A))
>>> assert(example.isSubclassA(example.B))
>>> assert(not example.isSubclassA(example.C))
>>> assert(example.func("test") == -1)
>>> assert(example.func(example.A()) == 0)
>>> assert(example.func(example.B()) == 1)
>>> assert(example.isSubclassA(example.A()))
>>> assert(example.isSubclassA(example.B()))
>>> assert(not example.isSubclassA(example.C()))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将类型对象(类,而不是实例)从 python 传递到 c++ 的相关文章

随机推荐

  • Actionscript-3和其他语言中存在接口的原因是什么

    这个接口的意义是什么 即使我们在一个类上实现一个接口 每次在不同的类上实现它时 我们都必须一次又一次地声明它的功能 那么接口存在于as3或任何其他具有接口的语言上的原因是什么 谢谢 我基本上同意到目前为止发布的答案 只是补充一点 首先回答简
  • 按名称返回所有因子水平作为三列 data.table [R] 中的新列

    有什么办法使用 data table 或 dplyr 来解决以下问题 library data table DT data table a LETTERS c 1 1 3 8 b c 2 4 7 c as factor c bob mary
  • 解码嗅探到的数据包

    我知道每个数据包都有一些标头 看起来像是字符的随机组合 另一方面 内容本身可以是纯 ascii 格式 因此它可能是人类友好的 我嗅探到的一些数据包是可读的 当然是原始的 html 标头 但有些数据包看起来像这样 0000 00 15 af
  • 合并列数据框

    我有以下数据框 df1 startTimeIso endTimeIso id 2023 03 07T03 28 56 969000 2023 03 07T03 29 25 396000 5 2023 03 07T03 57 08 73400
  • 具有多处理功能的 Tensorflow2.x 自定义数据生成器

    我刚刚升级到tensorflow 2 3 我想制作自己的数据生成器用于训练 使用tensorflow 1 x 我这样做了 def get data generator test flag item list load item list t
  • ActiveRecord:保存多个对象时跳过验证

    我知道我可以跳过单个保存的验证 如下所示 User new name John save validate false 但是 当同时保存多个对象时 我该如何做到这一点呢 像这样 Category create name Apps name
  • 在android应用程序中使用MediaPlayer的正确方法

    抱歉我的英语 但我来自巴西 我使用谷歌翻译 好吧 我在这个应用程序中遇到了困难 我试图制作一个在线广播流媒体 在 2 2 版本中工作正常 但在 4 0 版本中不起作用 没有发生错误 只是不起作用 下面是我的代码 我很感激任何帮助 packa
  • React Native Redux - 对象不是构造函数(评估“new ctor(props context)”)

    这是一个非常简单的页面 正在尝试使用 Redux 请参阅下面的代码 但是我收到错误object is not a constructor evaluating new ctor props context import React Comp
  • 根据所选值更改文本

    我为每个 JavaScript 添加了一个带有文本的元素 有了这个代码 document ready function if welcome page length my element after tr td td td Welcome
  • SQLAlchemy Joinedload过滤列

    您好 我想使用 joinload 对我的查询进行过滤 但我似乎无法让它发挥作用 以下是我的示例查询 result session query Work options joinedload Work company users joined
  • 单个 @RestController 端点的自定义序列化

    有没有一种方法 最好是某种类型的注释 为单个端点注册自定义序列化器 RestController 延伸豆子并放置一个 JsonSerialize这将是一个选项 但这需要一个非常无用的新 bean 类 我尝试了以下方法 JsonSeriali
  • 如何从 google chrome 扩展程序获取 PDF 文件的 URL

    去年 我开发了一个可处理 PDF 文件的 Google 扩展 我使用以下函数来获取 PDF 文件的 URL function getPDFUrl String const e document body firstElementChild
  • R 中的 Vlookup 匹配函数

    我对 R 非常陌生 目前我正在将我对 R 的了解很少应用到我必须执行的工作分析工作中 我有两个数据框 数据框 A 由交易详细信息组成 而数据框 B 由各种货币的月收盘汇率组成 数据框A 交易详情 TRANSACTION ID COLLECT
  • 如何在 RecyclerView.Adapter 中使用共享首选项?

    如何在 RecyclerView Adapter 中使用共享首选项 我在 RecyclerView Adapter 中使用了共享首选项值 但是共享首选项中没有保存任何内容 我必须在 RecyclerView Adapter 或活动中使用共享
  • 您能否在 Ajax (XHR) 调用的服务器端处理过程中可靠地设置或删除 cookie?

    我自己对此做了一些测试 准确地说是在 DWR 框架 Ajax 请求处理程序的服务器端处理期间 看来您可以成功地操作 cookie 但这与我在 Ajax 最佳实践中阅读的很多内容相悖浏览器如何解释来自 XmlHttpRequest 的响应 注
  • 无边框 NSWindow 上的圆角

    我正在创建一个应用程序并且我不需要标题栏 http www usabilitypost com 2010 10 22 no title bar If the title remains the same all the time does
  • 在nodejs中使用断言模块?

    大家好 我正在阅读node官方文档 我看到了 Assert 模块 但不明白它的用法 到目前为止我的结论是就像某些语言的 try catch 示例官方文档不足以让我理解该模块 你们能帮助我吗 这些将用于单元测试 该模块用于为您的应用程序编写单
  • 为什么 PyQt5 项目每次都会收到警告“QStandardPaths: XDG_RUNTIME_DIR not set”

    我正在使用 python 3 6 2 和 Emacs 25 在 Ubuntu 中开发 PyQt5 项目 并且它以 root 权限运行 这工作正常 但我得到了 QStandardPaths XDG RUNTIME DIR not set de
  • 在 slurm 上使用 python 的多处理

    我正在尝试在 slurm 上运行一些并行代码 其中不同的进程不需要进行通信 我天真地使用了 python 的 slurm 包 然而 我似乎只在一个节点上使用CPU 例如 如果我有 4 个节点 每个节点有 5 个 cpu 那么我只会同时运行
  • 将类型对象(类,而不是实例)从 python 传递到 c++

    我想要一个boost python wrappedC 函数能够接收类型 而不是实例 boost python 包装的 C 类 我可以声明包装的函数采用object 但是如何提取类型呢 我尝试过类似的方法 但类型对象似乎不是extract a