Вы можете приводить типы расширений к указателям и от них, используя синтаксис приведения к угловым скобкам. Часто стоит использовать тип 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*
, поэтому полезно его использовать. Если вы намереваетесь сохранить один из этих указателей, вам нужно увеличить счетчик ссылок, и вам следует уменьшить счетчик ссылок, когда вы закончите с ним.
Я не знаю точно, какой счетчик ссылок должен бытьсделано для вашего xor-ed списка, но вам нужно будет это сделать !
Здесь также потенциально может быть более тонкая проблема подсчета ссылок: если у вас есть циклические ссылки (например, если Node
содержит ссылку на XOrList
), тогда она никогда не будет освобождена. Cython пытается создать функции, которые обрабатывают циклические ссылки для классов cdef, однако он не понимает (и не может) понять, что вы делаете с указателями, поэтому они будут исключены;это не легко переопределить это поведение.