Cython, есть ли способ создавать списки только одного типа? (В отличие от списков Python) - PullRequest
3 голосов
/ 09 августа 2011

В моем классе Group должен быть атрибут particles, который должен иметь тип , похожий на массив, но иметь размер с изменяемым размером, который может содержать только экземпляры Particle.Оба класса, Group и Particle объявлены с использованием cdef.

Поскольку списки Python могут содержать любой объект Python, я подумал, что может быть более производительный способ объявления некоторого вида C-список, который принимает только Particle -инстанции.В Си это будет что-то вроде List<Particle> particle = new List<Particle>();, я думаю.

Есть ли какой-нибудь эквивалент для Cython или я должен просто остаться в списке Python?

Ответы [ 4 ]

2 голосов
/ 09 августа 2011

Да, вы можете просто использовать тот же векторный класс из cpp:

from libcpp.vector cimport vector

cdef class Item:
    cdef int amount
    cdef str description

def allocate():
    cdef vector[Item] bunch_of_items
    for i in xrange(100):
        bunch_of_items.push_back(Item())

Для компиляции:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext


ext = Extension(
    "extension_name",            
    ["module_name.pyx", ],     
    language="c++",         
    libraries=["stdc++"],
    cmdclass = {'build_ext': build_ext}
    )

setup(
    name = "name",
    cmdclass = {"build_ext": build_ext},
    ext_modules = [ext]
)

Только помните, что вы не можете передать этот список векторов обратно в python, если не конвертируете его в список питонов.

2 голосов
/ 09 августа 2011

Я не уверен, что вы достигнете какой-либо производительности, но если вы хотите убедиться, что список содержит только определенные виды данных ...

class Group(Object):
    #...
    def isParticle(self, p):
        return hasattr(p, "anAttributeOnlyParticlesHave")
    def getPartiles(self):
        return filter(self.isParticle, self._Particles)
    def setParticles(self, newParticles):
        self._Particles = filter(self.isParticle, newParticles)
    particles = property(getParticles, setParticles)

Опять же, это не так быстро, но это прямой ответ на ваш вопрос.

Вы можете получить что-то, написав модуль C - я не уверен. Если вам действительно нужна производительность, вы используете не тот язык.

Обычно с Python типичные уловки скорости не работают. Под капотом происходит достаточно кеширования и оптимизации, которые вы, как правило, не получаете, думая в терминах, подобных C - если вы не пишете модули на C.

1 голос
/ 10 августа 2011

Напрашивается вопрос: зачем вам это?

  • это для эффективности (зацикливание на массиве) или для уменьшения объема памяти?
  • вам нужен массив или связанного списка будет достаточно?
  • Ваш класс частиц - простая структура или что-то с поведением / методом?

В зависимости от этого, наилучшим решением будет использование массива python для numpy или контейнера stl.

(Обратите внимание, например, что циклический просмотр списка Python в Cython может быть весьма эффективным.)

0 голосов
/ 10 февраля 2019

Вы можете написать связанный список в виде структуры cython.Я установил для типа val значение int, но вы можете установить для него любой тип структуры.

from cpython.mem cimport PyMem_Malloc

cdef struct link:
    int val
    link *next


cdef link * create_link(int v, link *prev_link):
    cdef link *x = <link *>PyMem_Malloc(sizeof(link))
    x.val = v
    x.next = NULL
    if prev_link is not NULL:
        prev_link.next = x
    return x

Затем можно создать указатель на динамически размещаемые объекты ссылок.

cpdef many_links(int n):
    cdef link * l = NULL
    cdef link * f = NULL # keeps track of the first elem in the list 

    for i in range(n):
        l = create_link(i, l)
        if f == NULL:
            f = l

    # Write out the linked list to a python list
    cdef list r = []
    c = f
    while c.next != NULL:
        r.append(c.val)
        c = c.next
    r.append(c.val)

    return r
...