Как создать изменяемый массив объектов Python фиксированной длины в Cython? - PullRequest
7 голосов
/ 29 января 2011

Мне нужен массив объектов Python, которые будут использоваться при создании структуры данных.Мне нужна структура, которая будет фиксированной длины, как кортеж, и изменяемой, как список.Я не хочу использовать список, потому что я хочу быть в состоянии гарантировать, что список точно правильного размера (если он начинает выделять дополнительные элементы, накладные расходы памяти могут очень быстро возрастистановится больше).Есть ли способ сделать это?Я попытался создать массив объектов:

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

Каков наилучший способ сделать то, что я пытаюсь сделать?

Ответы [ 3 ]

5 голосов
/ 17 февраля 2011

Я не знаю о лучшем решении, но вот a решение:

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 *, если вы берете на себя ответственность за пересчет маленьких пуговиц. Это может быть большой головной болью для нетривиальных случаев.

1 голос
/ 29 января 2011

Если вам нужно всего несколько фиксированных размеров такой структуры, я бы посмотрел на создание классов с равномерно названным __slots__, включая один слот size для хранения размера. Вам нужно будет объявить отдельный класс для каждого размера (количество слотов). Определите функцию cdecl для доступа к слотам по индексу. Производительность доступа, вероятно, будет не такой высокой, как с простой адресной арифметикой массива C, но вы будете уверены, что слотов так много и больше.

0 голосов
/ 29 января 2011

Как насчет этого?

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)
...