【发布时间】:2019-10-17 11:36:50
【问题描述】:
作为练习,我将使用指针上的 XOR 组合一个双向链表,以方便每个节点只需存储一个值。我正在尝试使用对我来说是新的 Cython,我很快就制定了以下模式,但不知道 cython 的功能是否会按预期工作
cdef class Node:
def __init__(self, object val, void* prev_xor_next=NULL):
self.prev_xor_next=prev_xor_next
self.val=val
def __repr__(self):
return str(self.val)
cdef class CurrentNode(Node):
def __init__(self, Node node, void* prev_ptr=NULL):
self.node=node
self.prev_ptr=prev_ptr
cpdef CurrentNode forward(self):
if self.node.prev_xor_next:
return CurrentNode((self.node.prev_xor_next^self.prev_ptr)[0], &self.node)
cpdef CurrentNode backward(self):
if self.prev_ptr:
return CurrentNode(self.prev_ptr[0], (&self.node)^(self.prev_ptr[0]).prev_xor_next)
cdef class XORList:
cdef Node first, last, current
cpdef append(self, object val):
if not first:
self.first=CurrentNode(Node(val))
self.last=self.first
self.current=self.first
else:
if last==first:
self.last=CurrentNode(Node(val))
self.first.node.prev_xor_next=(&self.last.node)^self.first.prev_ptr
self.first=self.first.node
self.last.prev_ptr=&self.first
else:
temp=CurrentNode(Node(val))
self.last.node.prev_xor_next=(&self.temp.node)^self.last.prev_ptr
self.temp.prev_ptr=&self.last
self.last=temp
cpdef reverse(self):
temp=self.last
self.last=self.first
self.first=temp
def __iter__(self):
return self
def __next__(self):
if not self.current or not self.current.forward():
self.current=CurrentNode(self.first)
raise StopIteration()
ret = self.current
self.current=self.current.forward()
return ret
def __repr__(self):
cdef str ret =''
for i in self:
ret+='<=>'+str(i)
return ret
我遇到的问题包括获取指向扩展类型的指针和将指针传递给构造函数。我发现第二个问题是通过使用静态工厂方法解决的,但我把它留在这里,希望能保持我正在尝试的模式更清晰。
我尝试用结构替换 Node,但这让我无法将 python 对象作为 Node 的值。
我研究过 PyObject 和 PyCapsule,但我对它们都没有运气,这可能只是由于对它们的用法缺乏了解,尽管它们的基本用途似乎很清楚。
有没有一种方法可以使用 Cython 实现这种模式?
请原谅代码中的任何逻辑错误。我没有测试过,这只是一个练习。
【问题讨论】:
-
所以一般的问题是任何
def或cpdef(包括构造函数)都必须可以从 Python 调用,这意味着您不能传递不可表示为 PyObject 的类型。因此cdef静态构造函数是要走的路。我很确定会有重复的问题。 然而指针只是特殊的整数,所以你可以将它们作为整数传递给 Python(然后强制转换) -
这看起来也像是一个可能的引用计数灾难(尽管我不确定我是否遵循得足够好来确定)。每个
cdef类都被引用计数,但异或点不会保持对它的引用...... -
@DavidW 我也尝试过使用 uintptr_t 并在仍然使用 init 的同时进行强制转换,但是我更喜欢使用静态方法的解决方案。另外,我的理解是特殊方法必须声明为
def。如果您查看CurrentNode,您会看到我想要一个指向Node的实际指针。这是我无法通过任何其他更改解决的当前问题 -
是的,特殊方法必须是
def。您应该能够使用尖括号语法将指针投射到节点:<Node>。但是引用计数仍然是个问题。 -
@DavidW 您能否详细说明您对投射到节点的想法?最初的问题是无法获得指向 Node 对象的指针,那么还有什么可以转换的呢?
标签: python pointers linked-list cython