【问题标题】:How to access Python dunder methods in C using CFFI?如何使用 CFFI 在 C 中访问 Python dunder 方法?
【发布时间】:2020-10-25 20:19:05
【问题描述】:

我试图关注this example 尝试在 C 中创建一个可以在 Python 中使用的简单哈希表(使用 CFFI)。以下是对应的文件和相关代码。

hash_table.h:

typedef struct {
    size_t size;
    ...
    int cmp_function(const PyObject*, const PyObject*);
} hash_table_t;

build_hash_table.py:

from cffi import cffi

HEADER_FILE_NAME = "hash_table.h"
SOURCE_FILE_NAME = "hash_table.c"

ffi = FFI()

header = open(HEADER_FILE_NAME, "rt").read()
source = open(SOURCE_FILE_NAME, "rt").read()

ffi.set_source("hashtable.hash_table", header + source)
ffi.cdef(header)

if __name__ = "__main__":
    ffi.compile()

现在,到目前为止一切正常。但是,我将要在哈希表中插入任何数据类型。如何访问我在 C 代码中收到的任何对象?例如,假设我在 Python 中有这个类:

class Person():

    def __init__(self, name, id):
        self.name = name
        self.id = id

    def __eq__(self, other):
        return self.id == other.id

当我在哈希表中搜索Person 对象时,如何访问__eq__ 方法?正如你在上面看到的,我有一个在哈希表中声明为int cmp_function(const void*, const void*); 的通用比较函数。目标是每次搜索对象时,我都可以知道该对象的 __eq__ 方法定义 - 在 C 端。

希望我把我的问题说清楚了,提前谢谢你!

【问题讨论】:

  • 你的对象不应该是void *,而是PyObject * 那么...
  • 它们不应该是常量。无论如何,访问需要 CPython,在 PyPy 等中不起作用...
  • 如果我只是将它们用于比较,出于什么原因我不希望它们成为 const?无论哪种方式,我都可以只与 CPython 兼容的代码 - 当然,更便携的选项也很高兴:)

标签: c python-3.x python-cffi


【解决方案1】:

对于那些可能正在寻找另一个来比较 C 中的 Python 对象的人,我找到了 this question,它准确地解释了如何做到这一点。

【讨论】:

    【解决方案2】:

    见https://cffi.readthedocs.io/en/latest/using.html#extern-python-and-void-arguments。避免在 CFFI 中使用 PyObject *。正确答案是保留int cmp_function(const void*, const void*);。我将假设您已经使用 ffi.new_handle() 将对象转换为 void * 等价物,您可以发送到 C(在 add_to_hash_table() 方法等中)和 ffi.from_handle() 以读取它们(在 @987654330 @方法等)。

    要实现比较函数,您需要在 Python 中使用extern "Python" 声明一个函数,如上述文档中所示。然后将该函数用于结构中的cmp_function 指针。在该 Python 函数中,您将两个参数作为两个 void * 接收。您首先使用 ffi.from_handle() 将它们转换回原始 Python 对象,然后只使用常规 Python --- 在您的情况下,可能只是 if x == y: return 1; else: return 0 或类似的。

    在调用ffi.new_handle() 后,请注意保持 Python 对象处于活动状态。仅仅因为它们的void * 表示恰好存储在某些 C 结构中,它们并不能保持活力。

    请注意,CFFI 不太适合实现纯数据结构,因为与直接 CPython-C-API 方法相比,所有这些转换和多重存储都会增加开销。

    【讨论】:

    • 抱歉回复晚了。我还没有看到new_handle 和from_handle 函数。通过“用extern "Python"在Python中声明一个函数@你的意思是在C头文件中?至于比较函数,我需要知道如何比较C端的对象——如果我在哈希表,我需要知道该元素是否已经存在。所以我需要从 Python 中“检索”比较函数。
    • 另外关于 CFFI 不适合这份工作,我关注了these docs,它说 CFFI 会增加便携性。谢谢你的提醒:)
    • 引用:“例如,如果您的用例是调用 C 库函数或系统调用,则应考虑使用 ctypes 模块或 cffi 库,而不是编写自定义 C 代码。”请注意它如何提到调用库或系统调用,但没有实现纯数据结构。
    • 关于“在 Python 中使用 extern "Python" 声明一个函数:我的意思是在 URL cffi.readthedocs.io/en/latest/… 中有详细记录。
    猜你喜欢
    • 2022-01-06
    • 2015-08-24
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    • 2019-01-15
    • 2016-12-23
    • 2020-07-24
    • 2015-01-29
    相关资源
    最近更新 更多