问题标签 [pycxx]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
3914 浏览

python - Python 无法创建实例

我正在尝试使用PyCXX创建一个简单的 Python 扩展。我正在针对我的 Python 2.5 安装进行编译。

我的目标是能够在 Python 中执行以下操作:

但每次我尝试,这是我得到的错误:

TypeError: cannot create 'Kitty' instances

它确实Cats.Kitty被视为一个类型对象,但我无法创建 Kitty 类的实例,有什么想法吗?

这是我目前的来源:

0 投票
2 回答
1405 浏览

python - 使用 PyCxx 创建可继承的 Python 类型

我和一个朋友最近一直在玩弄各种 Python C++ 包装器,试图找到一个同时满足一些专业和业余项目需求的包装器。我们都在PyCxx上进行了磨练,作为轻量级和易于交互之间的良好平衡,同时隐藏了 Python C api 的一些最丑陋的部分。然而,PyCxx 在公开类型方面并不是非常健壮(即:它指示您创建类型工厂而不是实现构造函数),我们一直在努力填补空白,以便以更实用的方式公开我们的类型. 为了填补这些空白,我们求助于 C api。

然而,这给我们留下了一些问题,api 文档似乎没有深入介绍(当它涵盖时,答案有时是矛盾的)。基本的总体问题很简单:必须为 Python 类型定义什么才能用作基本类型?我们发现,要使 PyCxx 类作为类型起作用,我们需要显式定义 tp_new 和 tp_dealloc 并将类型设置为模块属性,并且我们需要在 [我们的类型]->tp_flags 上设置 Py_TPFLAGS_BASETYPE,但超出我们仍在黑暗中摸索。

到目前为止,这是我们的代码:

我们的 Python 测试代码如下所示:

奇怪的是,如果您将所有 meanKitty 位注释掉,脚本就会运行并且猫会喵喵叫,但是如果您取消对 meanKitty 类的注释,Python 会突然给我们这个:

这让我很困惑。就好像从它继承完全隐藏了基类!如果有人可以对我们缺少的内容提供一些见解,我们将不胜感激!谢谢!


编辑:好的,所以在发布这篇文章大约五秒钟后,我想起了我们之前想尝试的东西。我将以下代码添加到 kitty -

现在我们正在用 Python 对两只小猫喵喵叫!然而,仍然没有完全存在,因为现在我明白了:

所以还是在寻求帮助!谢谢!

0 投票
1 回答
375 浏览

python - 如何在 PyCXX 中访问 numpy 数组

我想将 numpy 数组转换为 c++ 端的一些 double* 或 stl 向量。我实际上为此使用了 PyCXX,但我无法弄清楚访问数据的方法。

我目前能够像这样访问和返回数据缓冲区:

但我不知道该怎么办。我的最终目标是从中获得一个 gsl_vector。理想情况下,我不必重新复制内存。但也许问得太多了;)

0 投票
1 回答
166 浏览

python - 在 PyCXX 扩展中定义属性的正确方法是什么

我想知道在使用 PyCxx 生成的 python 扩展中定义属性的正确方法是什么。目前我已经Py::PythonClass在官方示例中创建了一个 as 的子类。我behaviors().supportGetattro();在初始化函数中添加并创建了一个简单的覆盖

到目前为止,一切都很好。在 python 中,我得到了正确的值obj.name,但唯一让我不满意的是,调用属性时dir(obj)没有name列出。我该如何改变呢?

0 投票
1 回答
588 浏览

python - 使用 PyCXX 将模块加载到嵌入式 Python 运行时

我正在使用PyCXX围绕嵌入式 Python 运行时创建 C++ 包装器。

PyCXX 似乎没有可执行文件的示例,所以我正在尝试调整现有的示例代码。

我可以轻松启动并运行 Python 解释器:

这在我的 Xcode 调试/输出窗口中放置了一个功能齐全的 Python 提示符。

接下来,我公开了一个测试 C++ 类,以便它在 Python 中可见。range为此目的编写了一个类:

好的,所以这也有效。

但现在我正在尝试加载一个模块。

有一个名为“simple.cxx”的简单演示模块,其中包含:

并且simple_module该类派生自 PyCXX 的ExtensionModule类,该类派生自一个ExtensionModuleBase具有初始化程序的类:

如果我理解正确,预期用途是应该将此 .cxx 编译成一个库(OS X 上的 .so),并将其放在 Python 的搜索路径中的某个位置。

但是应该可以在无需编译单独的库的情况下使其工作。这就是我想要做的。

我在这里使用文档:https ://docs.python.org/3.4/extending/embedding.html它告诉我使用PyImport_AppendInittab.

现在我应该可以从提示中看到这个模块了。它被称为simple

它似乎没有奏效。

我错过了什么?

0 投票
2 回答
3152 浏览

python - PyCFunction_New / PyCFunction_NewEx 的文档

我正在努力理解一些围绕 PyCFunction_New 的PyCXX代码(C++ Python 包装器)。

有人能解释一下这个功能是如何工作的吗?

(我无法从 CPython源代码中弄清楚。)


在这里,我将详细说明我遇到的问题。我在上面划了一条线,因为这可能不会有那么普遍的用途。

问的原因是我正在处理奇怪的代码。我有一个关键字方法处理函数:

它被存储为:

然后它被捆绑到 PyCFunction_New 中:

我是否正确地假设 CPython 会负责将其类型转换回一个 3 参数函数,其中第一个参数是 args(它与处理程序的 _self_and_name_tuple 第一个参数匹配)?

而 CPython 只能从它必须解析的事实中知道:'myFunc(7, a=1)' 它实际上正在处理一个关键字 aka 3-param 函数?

这看起来不对。

也许 CPython 正在将 args 1类型转换回 PyMethodDef,然后检查它的 .ml_flags

如果发生这种情况,那么我需要知道,因为我正在使用的代码只是:

在它的原始形式中,我认为它一定有两个 PyMethodDef 副本并且第一个从未被触及,因为它是基类

如果这真的发生了,即如果这个类确实通过 PyCFunction_New 的内部将类型转换回 PyMethodDef,那么这是不可靠的。

当然有人可以在 MethodDefExt 的前面添加一个成员变量,然后类型转换就会中断。这是脆弱的...


我正在处理的类允许未来的 C++ 编码器实现自定义 Python 类型,并在此类型中实现可以从 Python 调用的方法。

所以他们派生MyExt : CustomExt并编写方法:

现在他们必须通过调用以下三个函数中的一个来将此方法存储在查找中:

请注意,每个都有一个关联的处理函数。这些处理函数是CustomExt的静态方法——因为指向静态方法的指针可以从CPython 中调用,即它只是一个标准的C 风格函数指针。

所以当 Python 想要这个foo函数的指针时,我们在这里截取:

构造一个 Python 函数,该函数将调用此方法的处理程序(同时在此对象 args[0] 中传递方法本身 args 1的详细信息)。处理程序将在捕获错误时负责运行该方法。

请注意,此时我们不执行处理程序而是将此 Python 函数返回给 Python 运行时 也许 Python 编码器不希望执行该函数,而只是想获取指向它的指针: fp = MyExt.func;

X (见下文) & method_def_ext->meth_def 拉出处理函数,它是三个处理函数之一然而,由于 MethodDefExt 的构造函数,它们都被类型转换为 PyCFunction 对象,这意味着参数列表对于关键字处理函数是错误的。

(我不得不打破注释,因为 SO 的格式化程序没有将它们作为代码注释处理)

我正在努力解决的是:假设foo是一个接受关键字的函数,所以它的签名将是:

匹配的处理程序如下所示:

即第三个。我读过 Python 提供了一个额外的第一个_self_and_name_tuple参数。

当我们将 foo 注册到查找中时,我们提供了这个处理程序:

并查看MethodDefExt的特定构造函数,

...可以看出它将这个处理程序类型转换为PyCFunction

但是PyCFunction只需要两个参数!!!

我们将处理程序类型转换为此。这些处理程序有 2 或 3 个参数。

这看起来真的很不对劲。

然后返回,所以当 CPython 想要执行 foo 时,如上所述,它将获取这个meth_def.ml_meth并将其输入PyCFunction_New

所以我可以猜测一下: * PyCFunction_New 的第一个参数必须是 PyCFunction 函数指针 * 第二个参数必须是 PyObject* _self_and_name_tuple

我们将这个反馈给 CPython 我的猜测是,当 CPython 想要使用 'foo(7, a=1,b=2)' 时,它会将 7 打包成 args,a=1,b=2 打包成 kwds,然后调用:

0 投票
2 回答
421 浏览

c++ - 使用模板将静态编码为实例方法蹦床功能

我正在尝试重新编码一些相当难看的模板编码。

作为参考,原文在这里:https ://codereview.stackexchange.com/questions/69545/recode-cc-trampoline-function-macros-using-templates

我的代码与 CPython(C 库)接口。Python 运行时看到 "myInst.foo" ,在表中查找 "foo" 并调用:

(请注意,可以将静态方法类型转换为 C 函数指针)

FooHandler 跳转到正确的 Final 实例的 Foo 方法。

实际上,句柄并不那么干净,并且有许多方法,每个方法都需要相同的处理程序(但具有不同的函数地址)。

我试图将处理程序机制抽象为一个基类,如下所示:

我目前陷入编译器错误(http://ideone.com/vOtbcD),所以我什至不确定该技术是否有效。

有什么方法可以做到这一点,或者这只是你真正需要宏的时候之一?

作为参考,原文在这里:https ://codereview.stackexchange.com/questions/69545/recode-cc-trampoline-function-macros-using-templates

可以看出,原始版本使用了相当丑陋的宏。

0 投票
2 回答
359 浏览

memory-management - C-API:分配“PyTypeObject-extension”

0 投票
2 回答
700 浏览

python - Windows 中的延迟加载

我试图了解一些代码(直接从 PyCXX 改编)。它是一个多平台 C++ Python 包装器。

编辑:这里的原始代码。

它似乎迎合了一些只存在于 Windows 中的特殊现象:

我将在下面给出完整的文件列表,它很长。

这个 PY_WIN32_DELAYLOAD_PYTHON_DLL 令牌在 CPython 中不存在,它也没有在 PyCXX 中定义。因此我只能想象 PyCXX 打算将它作为可选的编译器标志提供。

我想知道的是:它的目的是什么?它在解决什么问题?为什么这种机制甚至存在?

也许熟悉Windows编程的人可以从代码中弄清楚?

我想知道它正在解决的问题是否仍然存在于现代 Windows 中,因为代码已经超过 15 年了。

关键问题是:我可以删除它,还是用更清洁的东西代替它?

我非常想把它剪掉;但它在现代 Windows 环境中仍然有一些有用的用途吗?

代码:

0 投票
1 回答
306 浏览

c++ - 为什么 PyCXX 会以它的方式处理新式类?

我正在挑选一些 C++ Python 包装器代码,这些代码允许消费者从 C++ 构建自定义的旧样式和新样式 Python 类。

原始代码来自PyCXX ,这里这里都有新旧样式类。然而,我已经大量重写了代码,在这个问题中,我将参考我自己的代码,因为它使我能够以最清晰的方式呈现情况。我认为如果没有几天的审查,很少有人能够理解原始代码......对我来说,这已经花费了数周时间,但我仍然不清楚。

旧样式只是派生自 PyObject,

当 one_time_setup() 被调用时,它强制(通过访问基类typeobject())为这个新类型创建关联PyTypeObject

稍后在构造实例时,它使用PyObject_Init

到目前为止,一切都很好。

但是新样式类使用更复杂的机器。我怀疑这与新样式类允许派生的事实有关。

这是我的问题,为什么新样式类处理是以它的方式实现的?为什么必须创建这个额外的 PythonClassInstance 结构?为什么它不能像旧式的类处理那样做事情呢?即只需从 PyObject 基本类型输入转换?并且看到它没有这样做,这是否意味着它没有使用它的 PyObject 基本类型?

这是一个很大的问题,我将继续修改帖子,直到我满意它很好地代表了这个问题。它不适合 SO 的格式,对此我很抱歉。然而,一些世界级的工程师经常光顾这个网站(例如,我之前的一个问题是由 GCC 的首席开发人员回答的),我很重视利用他们的专业知识的机会。所以请不要太仓促投票关闭。

新样式类的一次性设置如下所示:

所以新样式使用了一个自定义的 PythonClassInstance 结构:

PyObject_HEAD,如果我深入研究 Python 的 object.h,它只是一个宏PyObject ob_base;——没有其他复杂性,例如 #if #else。所以我不明白为什么它不能简单地是:

甚至:

无论如何,它的目的似乎是将指针标记到 PyObject 的末尾。这是因为 Python 运行时经常会触发我们放在其函数表中的函数,而第一个参数将是负责调用的 PyObject。因此,这允许我们检索关联的 C++ 对象。

但是我们也需要对旧式类这样做。

这是负责执行此操作的函数:

我的评论表达了我的困惑。

在这里,为了完整起见,我们将 lambda-trampoline 插入到 PyTypeObject 的函数指针表中,以便 Python 运行时可以触发它:

(在这个演示中,我使用了 tp_setattro,请注意还有大约 30 个其他插槽,如果您查看 PyTypeObject 的文档,您可以看到)

(事实上​​,以这种方式工作的主要原因是我们可以在每个蹦床上尝试{}catch{}。这使消费者不必编写重复的错误捕获代码。)

因此,我们提取“关联 C++ 对象的基本类型”并调用它的虚拟 setattro(此处仅以 setattro 为例)。派生类将覆盖 setattro,并且将调用此覆盖。

旧式类提供了这样的覆盖,我将其标记为 MARKER1——它位于该问题的顶部列表中。

我唯一能想到的是,也许不同的维护者使用了不同的技术。但是,新旧风格的类需要不同的架构,还有什么更令人信服的理由吗?


PS作为参考,我应该包括来自新样式类的以下方法:

^ 对我来说,这看起来完全错误。它似乎正在分配内存,重新转换到可能超过分配数量的某些结构,然后在此结束时清空。我很惊讶它没有导致任何崩溃。我在源代码中的任何地方都看不到这 4 个字节是拥有的。

^ 请注意,除了默认值之外,没有 reinit 的实现


编辑:我会冒险猜测,这要归功于 IRC 频道上 Yhg1s 的洞察力。

也许是因为当你创建一个新的老式类时,它保证它会完美地重叠一个 PyObject 结构。

因此,从 PyObject 派生并将指向底层 PyObject 的指针传递给 Python 是安全的,这就是旧式类所做的 (MARKER2)

另一方面,新样式类创建了一个 {PyObject + 也许是别的} 对象。ie 做同样的把戏是不安全的,因为 Python 运行时最终会写到基类分配的末尾(它只是一个 PyObject)。

因此,我们需要让 Python 为类分配,并返回一个我们存储的指针。

因为我们现在不再使用 PyObject 基类进行存储,所以我们不能使用类型转换的便捷技巧来检索关联的 C++ 对象。这意味着我们需要在实际分配的 PyObject 末尾标记一个额外的 sizeof(void*) 字节,并使用它来指向我们关联的 C++ 对象实例。

然而,这里有些矛盾。

^ 如果这确实是完成上述内容的结构,那么它就是说新样式类实例确实完全适合 PyObject,即它没有重叠到 m_pycxx_object 中。

如果是这样的话,那么整个过程肯定是不必要的。

编辑:这里有一些链接可以帮助我学习必要的基础工作:

http://eli.thegreenplace.net/2012/04/16/python-object-creation-sequence
http://realmike.org/blog/2010/07/18/introduction-to-new-style-classes-in -python
使用 Python 的 C API 创建一个对象