【问题标题】:How do I create a fixed-length, mutable array of Python objects in Cython?如何在 Cython 中创建一个固定长度、可变的 Python 对象数组?
【发布时间】:2011-06-17 13:39:51
【问题描述】:

我需要一个 python 对象数组来创建 trie 数据结构。我需要一个结构,它像元组一样是固定长度,像列表一样是可变的。我不想使用列表,因为我希望能够确保列表的大小完全正确(如果它开始分配额外的元素,内存开销可能会随着特里长得更大)。有没有办法做到这一点?我尝试创建一个对象数组:

cdef class TrieNode:
    cdef object members[32]

...但这给出了一个错误:

Error compiling Cython file:
------------------------------------------------------------
...
cdef class TrieNode:
    cdef object members[32]
                      ^
------------------------------------------------------------

/Users/jason/src/pysistence/source/pysistence/trie.pyx:2:23: Array element cannot be a Python object

做我想做的事情的最佳方法是什么?

【问题讨论】:

    标签: python arrays cython trie python-c-extension


    【解决方案1】:

    我不知道最佳解决方案,但这里有一个解决方案:

    from cpython.ref cimport PyObject, Py_XINCREF, Py_XDECREF
    
    DEF SIZE = 32
    
    cdef class TrieNode:
        cdef PyObject *members[SIZE]
    
        def __cinit__(self):
            cdef object temp_object
            for i in range(SIZE):
                temp_object = int(i)
                # increment its refcount so it's not gc'd.
                # We hold a reference to the object and are responsible for
                # decref-ing it in __dealloc__.
                Py_XINCREF(<PyObject*>temp_object)
                self.members[i] = <PyObject*>temp_object
    
        def __init__(self):
            # just to show that it works...
            for i in range(SIZE):
                print <object>self.members[i]
    
        def __dealloc__(self):
            # make sure we decref the members elements.
            for i in range(SIZE):
                Py_XDECREF(self.members[i])
                self.members[i] = NULL
    

    Cython object 是自动引用的 PyObject *。只要您负责引用小虫子,您就可以随时滚动您自己的PyObject * 数组。对于非平凡的案例来说,这可能是一个令人头疼的问题。

    【讨论】:

      【解决方案2】:

      如果您只需要这种结构的几个固定大小,我会考虑制作具有统一命名__slots__ 的类,包括一个size 插槽来存储大小。您需要为每个大小(插槽数)声明一个单独的类。定义一个 cdecl 函数以按索引访问插槽。访问性能可能不如 C 数组的普通地址算术那么好,但您会确定只有这么多插槽,没有更多。

      【讨论】:

        【解决方案3】:

        这个怎么样?

        class TrieNode():
           def __init__(self, length = 32):
              self.members = list()
              self.length = length
              for i in range(length):
                 self.members.append(None)
        
           def set(self, idx, item):
              if idx < self.length and idx >= 0:
                 self.members[idx] = item
              else:
                 print "ERROR: Specified index out of range."
                 # Alternately, you could raise an IndexError.
        
           def unset(self, idx):
              if idx < self.length and idx >= 0:
                 self.members[idx] = None
              else:
                 raise IndexError("Specified index out of range (0..%d)." % self.length)
        

        【讨论】:

        • 我的偏好是assert 0 &lt;= idx &lt; self.length, "index out of range" 比整个if-else 构造要小得多。
        • 对不起,但这甚至不在我正在寻找的正确范围内。两件事:1)我正在寻找一种在 cython 中执行此操作的方法来创建 C 扩展。 2) 我没有办法强制列表恰好占据 32 个元素。它的 len 为 32,但通常会分配更多空间以使追加更容易。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多