作为练习,我将对指针使用XOR组合成一个双向链接列表,以方便每个节点仅存储一个值。我正在尝试使用对我来说是新的Cython,我迅速绘制了以下模式,却不知道cython的功能是否可以按预期工作
$whereRaw = DB::connection()->getPdo()->quote(' "table"."json_field"::jsonb ?| array["test", "test2"] ');
ExampleModel::whereRaw($whereRaw)->get();
我遇到的问题包括获取指向扩展类型的指针以及将指针传递给构造函数。我发现其中的第二个问题是通过使用静态工厂方法解决的,但我将其留在此处,以希望保持我正在尝试的模式更清晰。
我尝试用结构替换Node,但这使我无法将python对象作为Node的值。
我已经研究了PyObject和PyCapsule,但我对它们都不满意,这可能是由于尽管他们的基本目的似乎很明确,但由于对它们的用法缺乏了解。
是否有一种方法可以使用Cython进行这种模式?
请原谅代码中的任何逻辑错误。我还没有测试过,它只是一种练习。
答案 0 :(得分:2)
您可以使用尖括号转换语法将扩展类型与指针进行转换。通常值得使用PyObject*
类型的cimport from cpython.object
,但是也可以直接转到void*
:
from cpython.object cimport PyObject
cdef Node n = Node()
cdef PyObject* nptr1 = <PyObject*>n
cdef void* nptr2 = <void*>n
cdef void* nptr3 = <void*>nptr1
要返回到cdef类型,请执行以下操作:
cdef Node new_node = <Node>nptr1
Cython不允许您做的一件事是:
# ERROR: Storing unsafe C derivative of temporary Python reference
cdef PyObject* bad = <PyObject*>Node()
它意识到新的Node
几乎在创建后就将不复存在,因此指针立即无效。相反,nptr1
,nptr2
和nptr3
的有效期至少只要不重新分配n
即可。
请注意,您必须自己处理这些参考计数。您可以再次使用cimport
访问相关功能:from cpython.ref cimport Py_XINCREF, Py_XDECREF
。这些函数采用PyObject*
,因此使用它很有用。如果要存储这些指针之一,则需要增加引用计数,并在完成操作后减少引用计数。
我不确切知道应该对您的异或列表执行什么引用计数,但是您将需要这样做!
这里也可能存在一个更细微的引用计数问题:如果您有循环引用(例如,Node
包含指向XOrList
的链接),那么它将永远不会被释放。 Cython尝试生成处理cdef类的循环引用的函数,但是它不(也无法)理解您对指针所做的操作,因此将其排除在外。覆盖这种行为并不容易。