Cython:访问 CPython 对象的私有 C 成员

Cython: Access to private C members of CPython object

http://docs.cython.org/src/userguide/extension_types.html#external-extension-types 中解释了如何访问 Python 扩展模块中对象的内部(隐藏或 "private")C 级成员。

我想从 sqlite3.Connection 对象访问内部成员 db,该对象在 Python 的文件 Modules/_sqlite/connection.h 的结构 pysqlite_Connection 中定义2 来源。我是这样做的:

文件connection.pxd:

cdef extern from "connection.h":
    struct sqlite3Connection:
        sqlite3 *db

    ctypedef class __builtin__.xConnection [object pysqlite_Connection]:
        cdef sqlite3Connection conn

然后像这样使用它:

文件vtables.pxd:

from connection cimport xConnection

cdef dbname(xConnection c):
    cdef sqlite3 *d
    return sqlite3_db_filename(c.conn.db, "main")

这是用 cython 编译的,但是 当我 运行 C 编译器的结果时,我得到:

vtables.c:635:69: error: ‘pysqlite_Connection’ has no member named ‘conn’
   __pyx_t_1 = __Pyx_PyBytes_FromString(sqlite3_db_filename(__pyx_v_c->conn.db, __pyx_k_main)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
                                                                     ^

生成的 C 代码似乎就像我正在访问 pysqlite_Connection 结构而不是包装 xConnection,抱怨访问成员 conn 当然不是在 pysqlite_Connection 但在我的 xConnection Cython class 中。但是在dbname函数中参数明确定义为xConnection。这似乎是 cython 编译器中的错误。还是我错过了什么?

我尝试按照文档中的方式提供 type 参数,例如:

ctypedef class __builtin__.xConnection [object pysqlite_Connection, type pysqlite_ConnectionType]:
    cdef sqlite3Connection conn

但是 cython 崩溃了。

如果此方法 obsolete/not 不再受支持,是否还有其他选择?

我不认为你已经完成了你认为你已经完成的事情。您尚未创建名为 xConnection 的包装器 class。您已经向 Cython 保证已经有一个名为 __builtin__.xConnection 的 class 并且它是使用 C 结构 pysqlite_Connection 存储的,并且它包含一个 sqlite3Connection 结构,其中包含一个成员称为 db.

我想你想告诉 Cython 的是,已经有一个名为 sqlite.Connection 的 class,它存储在 C 结构 pysqlite_Connection 中,其中包含一个名为 db:

cdef extern from "connection.h":
    # I assume you definite this somewhere else
    ctypedef struct sqlite3:
        pass

    ctypedef class sqlite.Connection [object pysqlite_Connection]:
        cdef sqlite3* db

cdef dbname(Connection c):
    return sqlite3_db_filename(c.db, "main")