如何在 Python C-API 中动态创建派生类型

2024-02-27

假设我们有类型Noddy如定义在为 Python 编写 C 扩展模块的教程 http://docs.python.org/extending/newtypes.html#adding-data-and-methods-to-the-basic-example。现在我们要创建一个派生类型,仅覆盖__new__()的方法Noddy.

目前我使用以下方法(为了可读性而删除错误检查):

PyTypeObject *BrownNoddyType =
    (PyTypeObject *)PyType_Type.tp_alloc(&PyType_Type, 0);
BrownNoddyType->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
BrownNoddyType->tp_name = "noddy.BrownNoddy";
BrownNoddyType->tp_doc = "BrownNoddy objects";
BrownNoddyType->tp_base = &NoddyType;
BrownNoddyType->tp_new = BrownNoddy_new;
PyType_Ready(BrownNoddyType);

这可行,但我不确定这是否是正确的方法。我原以为我必须设置Py_TPFLAGS_HEAPTYPE http://docs.python.org/c-api/typeobj.html#Py_TPFLAGS_HEAPTYPE标志,因为我在堆上动态分配类型对象,但这样做会导致解释器中出现段错误。

我也考虑过明确调用type() using PyObject_Call()或类似的,但我放弃了这个想法。我需要包装该函数BrownNoddy_new()在 Python 函数对象中并创建字典映射__new__对于这个函数对象,这看起来很愚蠢。

解决这个问题的最佳方法是什么?我的做法正确吗?是否有我错过的接口功能?

Update

python-dev 邮件列表上有两个关于相关主题的线程(1) http://mail.python.org/pipermail/python-dev/2009-July/090875.html (2) http://mail.python.org/pipermail/python-dev/2009-August/091192.html。从这些线程和一些实验中,我推断我不应该设置Py_TPFLAGS_HEAPTYPE除非该类型是通过调用分配的type()。这些线程中有不同的建议,是手动分配类型更好还是调用type()。如果我知道包装 C 函数的推荐方法是什么,我会对后者感到满意。tp_new斯槽群岛对于常规方法,这一步很简单——我可以使用PyDescr_NewMethod() http://docs.python.org/c-api/descriptor.html#PyDescr_NewMethod获得合适的包装对象。我不知道如何为我的对象创建这样的包装对象__new__()不过,方法——也许我需要未记录的函数PyCFunction_New()创建这样一个包装对象。


当我修改扩展以与Python 3兼容时,我遇到了同样的问题,并在尝试解决它时找到了这个页面。

我最终通过阅读Python解释器的源代码解决了这个问题,PEP 0384 https://www.python.org/dev/peps/pep-0384/以及文档C-API https://docs.python.org/3/c-api/type.html?highlight=pytype_fromspec.

设置Py_TPFLAGS_HEAPTYPEflag 告诉口译员重铸你的PyTypeObject as PyHeapTypeObject,其中包含也必须分配的其他成员。在某些时候,解释器会尝试引用这些额外的成员,如果您不分配它们,则会导致段错误。

Python 3.2 引入了 C 结构PyType_Slot and PyType_Spec和 C 函数PyType_FromSpec简化动态类型的创建。简而言之,您使用PyType_Slot and PyType_Spec指定tp_*的成员PyTypeObject然后打电话PyType_FromSpec完成分配和初始化内存的脏活。

从 PEP 0384 开始,我们有:

typedef struct{
  int slot;    /* slot id, see below */
  void *pfunc; /* function pointer */
} PyType_Slot;

typedef struct{
  const char* name;
  int basicsize;
  int itemsize;
  int flags;
  PyType_Slot *slots; /* terminated by slot==0. */
} PyType_Spec;

PyObject* PyType_FromSpec(PyType_Spec*);

(以上内容并非 PEP 0384 的原版,其中还包括const char *doc作为成员PyType_Spec。但该成员没有出现在源代码中。)

要在原始示例中使用这些,假设我们有一个 C 结构,BrownNoddy,扩展基类的 C 结构Noddy。那么我们就会:

PyType_Slot slots[] = {
    { Py_tp_doc, "BrownNoddy objects" },
    { Py_tp_base, &NoddyType },
    { Py_tp_new, BrownNoddy_new },
    { 0 },
};
PyType_Spec spec = { "noddy.BrownNoddy", sizeof(BrownNoddy), 0,
                      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots };
PyTypeObject *BrownNoddyType = (PyTypeObject *)PyType_FromSpec(&spec);

这应该完成原始代码中的所有操作,包括调用PyType_Ready,加上创建动态类型所需的内容,包括设置Py_TPFLAGS_HEAPTYPE,并分配和初始化额外的内存PyHeapTypeObject.

我希望这有帮助。

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

如何在 Python C-API 中动态创建派生类型 的相关文章

随机推荐

  • MessageKit 不显示消息输入栏 Swift 5

    这是控制器层次结构 tabBarController gt 一些控制器和聊天频道控制器 并且这个聊天频道控制器也是一个导航控制器 当我选择行时 它会推送到 MessageViewController 类的聊天控制器 我这里有两个问题 一是小
  • 为什么使用 Tiled 的 libgdx 游戏中出现线条?

    我正在使用 LibGdx 和 Tiled 当在屏幕上移动时 游戏上会出现水平线和垂直线 如果需要的话 我可以发布您需要的任何代码 我怎样才能让这些线路停止 这是一个 gfycat gif 的线条 http gfycat com FastUn
  • QML - MouseArea/MouseEvent 问题

    下面的代码生成一个白色矩形 其中包含一个红色矩形和一个灰色矩形 每个矩形都有一个关联的 MouseArea 当鼠标在灰色矩形内单击时 灰色矩形会变成蓝色 当鼠标光标进入红色矩形内部时 红色矩形会打印一条控制台消息 当发出释放信号时 会打印另
  • 我如何比较“Bcrypt”Gem 解密的密码和加密的密码

    我正在尝试对某些帖子的评论使用简单的身份验证 用户使用即时 ID 和密码输入评论 我使用 bcrypt gem 将密码存储在数据库中 就像comments controller rb中这样 comment Comment new comme
  • Django 中子查询的查询

    我正在尝试从另一个查询执行查询 但 Django 说 渲染时捕获数据库错误 子查询返回超过 1 行 我正在使用 PostGis my model class Place models Model coordinate models Poin
  • 通过 .htaccess 文件为所有 PHP 脚本设置 HTTP 标头

    我在我的一个项目中对所有 PHP 程序编写了相同的代码行 是否可以在目录的 htaccess 中执行此操作 如何 PHP 代码 Header Content Type application xhtml xml charset utf 8
  • 混淆矩阵和列联表有什么区别?

    我正在编写一段代码来评估我的聚类算法 我发现每种评估方法都需要来自m n类似矩阵A aij where aij是属于类成员的数据点的数量ci和簇的元素kj 但似乎有两个这种类型的矩阵数据挖掘简介 Pang Ning Tan 等 一个是混淆矩
  • iOS:无法启动 .app 文件

    我不知道为什么它在我的 app 文件中寻找目录 每次我运行应用程序时 它都会在 iPhone 上安装应用程序 但不会运行并给出以下错误 谁能告诉我这个设置存储在哪里 谢谢 error failed to launch Users xxx L
  • 更新/替换 Google 文档上的内嵌图像

    我正在尝试设置一个功能来更新 Google 文档上的图像 就像 Lucidchart Add on 对其 更新插入图表 功能所做的那样 为此 我目前正在执行以下操作 创建命名范围并将其 id 与生成图像的数据一起存储在文档属性中 以供以后检
  • 内部 __lzcnt64 使用不同的编译选项返回不同的值

    我有以下代码 include
  • BindingResult 和 bean 名称“categoryOptions”的普通目标对象都不能作为请求属性

    我知道这个主题有很多线程 我已经尝试了其中的大多数 但仍然无法解决我的问题 我正在使用SpringMVC and MongoDB我想要实现的是 我将在数据库中存储一些数据 然后将其从数据库检索回选择选项 这是我的代码 Jsp页面
  • SQLite:结束事务花费的时间太长

    我正在事务中插入几行 但是 当我执行 END TRANSACTION 时 执行时间约为 250 毫秒 而 BEGIN TRANSACTION 则几乎不需要 1 毫秒左右 我需要加快这里的速度以适应我的应用程序 我怎么能够 编辑 单线程正在访
  • SSL:CERTIFICATE_VERIFY_FAILED 证书验证失败:自签名证书(_ssl.c:1129)

    我正在尝试自动创建受信任的证书和非对称密钥 然后执行自动安装过程 目前 所有这些都是使用 OpenSSL 实用程序手动完成的 我正在使用 Cryptography io 库来实现此自动化 并尝试使用代码生成的证书连接到服务器 当我调用 Po
  • Symfony2 - 从编译器通道访问内核

    有没有办法从编译器通道内部访问内核 我试过这个 public function process ContainerBuilder container kernel container gt get kernel 这会引发错误 还有其他方法吗
  • 是否可以从 Silverlight / C# 调用 matlab 函数?

    是否可以从 Silverlight C 调用 matlab 函数 如果您有一个可以解释 Mathlab 调用的程序集 dll 您应该能够将该程序集包含在您的项目中 并将其与应用程序的其余部分一起编译 显然 您将无法并行运行 Silverli
  • 为什么我的 Android ListAdapter 只显示一项?

    在我的 Android 应用程序中 我正在尝试构建我的第一个自定义列表适配器 我现在设法让它显示一项 但不幸的是 列表中有 8 个项目时 只能显示一项 我的适配器如下所示 public class PossibilitiesAdapter
  • 如何为自定义数组类型重载 Base.show ?

    假设我用它自己的自定义来制作我自己的自定义向量类型show method struct MyVector T lt AbstractVector T v Vector T end function Base show io IO v MyV
  • 如何访问 tf.data.Dataset.list_files() 收集的文件名?

    我在用 file data tf data Dataset list files png 收集图像文件以在 TensorFlow 中进行训练 但希望访问收集的文件名列表 以便执行标签查找 调用 sess run file data 一直不成
  • 将巨大的模型对象保存到文件中

    假设您有一个从 VAR 回归操作返回的 varrest 类模型对象 我想将模型保存到文件中 但不是用于估计系数的所有数据 如何只保存模型规范而不保存训练数据 因为当我保存模型时 它的文件大小超过 1GB 因此加载确实需要时间 可以保存没有某
  • 如何在 Python C-API 中动态创建派生类型

    假设我们有类型Noddy如定义在为 Python 编写 C 扩展模块的教程 http docs python org extending newtypes html adding data and methods to the basic