How do I create a fixed-length, mutable array of Python objects in Cython?

有些话、适合烂在心里 提交于 2019-12-12 07:59:43

问题


I need to have an array of python objects to be used in creating a trie datastructure. I need a structure that will be fixed-length like a tuple and mutable like a list. I don't want to use a list because I want to be able to ensure that the list is exactly the right size (if it starts allocating extra elements, the memory overhead could add up very quickly as the trie grows larger). Is there a way to do this? I tried creating an array of objects:

cdef class TrieNode:
    cdef object members[32]

...but that gave an error:

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

What is the best way to do what I'm trying to do?


回答1:


I don't know about the best solution, but here's a solution:

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

A Cython object is an automatically refcounted PyObject *. You can always roll your own arrays of PyObject *'s as long as you take responsibility for refcounting the little buggers. This can be a major headache for non-trivial cases.




回答2:


If you only need few fixed sizes of such a structure, I'd look at making classes with uniformly named __slots__, including one size slot to store the size. You'll need to declare a separate class for each size (number of slots). Define a cdecl function to access slots by index. Access performance will probably be not as great as with plain address arithmetics of a C array, but you'll be sure that there's only so many slots and none more.




回答3:


How about this?

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)


来源:https://stackoverflow.com/questions/4834036/how-do-i-create-a-fixed-length-mutable-array-of-python-objects-in-cython

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!