cython:如何创建cdef类的数组 [英] cython: how do you create an array of cdef class

查看:462
本文介绍了cython:如何创建cdef类的数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要一个cdef类的cython数组:

I would like to have a cython array of a cdef class:

cdef class Child:
    cdef int i

    def do(self):
        self.i += 1

cdef class Mother:
    cdef Child[:] array_of_child

    def __init__(self):
        for i in range(100):
            self.array_of_child[i] = Child()


推荐答案

答案是否定的-不可能以一种有用的方式实现:基本上是相同问题的新闻组帖子

The answer is no - it is not really possible in a useful way: newsgroup post of essentially the same question

不可能有 Child s的直接数组(分配在单个块中)。部分原因是,如果其他地方引用了数组中的 Child ,则必须保持该 Child 的生命。 (而不是整个数组),这将无法确保它们是否都分配在同一块内存中。另外,如果要调整数组的大小(如果需要),那么它将使对该数组内对象的其他引用无效。

It wouldn't be possible to have a direct array (allocated in a single chunk) of Childs. Partly because, if somewhere else ever gets a reference to a Child in the array, that Child has to be kept alive (but not the whole array) which wouldn't be possible to ensure if they were all allocated in the same chunk of memory. Additionally, were the array to be resized (if this is a requirement) then it would invalidate any other references to the objects within the array.

因此,您剩下的就是具有指向 Child 的指针数组。这样的结构会很好,但是在内部看起来几乎就像是Python列表(因此,在Cython中执行更复杂的操作确实没有任何好处。)。

Therefore you're left with having an array of pointers to Child. Such a structure would be fine, but internally would look almost exactly like a Python list (so there's really no benefit to doing something more complicated in Cython...).

有一些明智的解决方法:

There are a few sensible workarounds:


  1. 新闻组帖子中建议的解决方法仅是使用python列表。您还可以将numpy数组与 dtype = object 一起使用。如果需要访问该类中的cdef函数,则可以先进行强制转换:

  1. The workaround suggested in the newsgroup post is just to use a python list. You could also use a numpy array with dtype=object. If you need to to access a cdef function in the class you can do a cast first:

cdef Child c = <Child?>a[0] # omit the ? if you don't want
                            # the overhead of checking the type.
c.some_cdef_function()

内部,这两个选项都存储为 PyObject 指向 Child 对象的指针,因此效率不如您想象的那么低。

Internally both these options are stored as an C array of PyObject pointers to your Child objects and so are not as inefficient as you probably assume.

另一种可能是将数据存储为C结构( cdef结构ChildStruct:.... ),这很容易存储为数组。当您需要该结构的Python接口时,可以定义 Child ,以便它包含 ChildStruct 的副本(但可以进行修改)不会传播回原始数组)或指向 ChildStruct 的指针(但您需要注意确保不会释放孩子指向它还活着。)

A further possibility might be to store your data as a C struct (cdef struct ChildStruct: ....) which can be readily stored as an array. When you need a Python interface to that struct you can either define Child so it contains a copy of ChildStruct (but modifications won't propagate back to your original array), or a pointer to ChildStruct (but you need to be careful with ensuring that the memory is not freed which the Child pointing to it is alive).

您可以使用 Numpy结构化数组-这与使用C结构数组非常相似,除了Numpy处理内存,并提供Python接口。

You could use a Numpy structured array - this is pretty similar to using an array of C structs except Numpy handles the memory, and provides a Python interface.

问题中的memoryview语法是否有效 cdef Child [:] array_of_child 。可以从dtype object 的numpy数组初始化:

The memoryview syntax in your question is valid: cdef Child[:] array_of_child. This can be initialized from a numpy array of dtype object:

array_of_child = np.array([(Child() for i in range(100)])

关于数据结构,这是一个指针数组(即与Python列表相同,但可以是多维的),避免了< Child> 它不执行的重要操作是任何类型检查-如果将不是 Child 的对象提供给数组,那么它不会注意到(因为底层的 dtype object ),但是会给出无意义的答案或分段错误

In terms of data-structure, this is an array of pointers (i.e. the same as a Python list, but can be multi-dimensional). It avoids the need for <Child> casting. The important thing it doesn't do is any kind of type-checking - if you feed an object that isn't Child into the array then it won't notice (because the underlying dtype is object), but will give nonsense answers or segmentation faults.

在我看来,这种方法使您对两件事产生了错误的安全感:首先,您制作了一个更有效的数据结构(实际上,您没有这样做, (与列表相同);其次,您具有任何类型的类型安全性,但是,它确实存在(如果要使用内存视图,例如对于多维数组,我使用类型为 object 的memoryview可能会更好-这对基础dtype很老实)

In my view this approach gives you a false sense of security about two things: first that you have made a more efficient data structure (you haven't, it's basically the same as a list); second that you have any kind of type safety. However, it does exist. (If you want to use memoryviews, e.g. for multi-dimensional arrays, it would probably be better to use a memoryview of type object - this is honest about the underlying dtype)

这篇关于cython:如何创建cdef类的数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆