按cdef类中的属性对cdef对象列表进行排序

时间:2016-06-01 23:14:20

标签: python sorting cython

我想对此类的inner列表进行排序。该列表包含名为Edge的cdef类的对象。 Edge类包含一个名为savings的成员变量。我想按此变量对列表进行排序。

cdef class Alist:
    def __init__(self):
        self.inner = []
    cdef list inner
    cdef void append(self, Edge a):
        self.inner.append(a)
    cdef void pop(self, int a):
        self.inner.pop(a)
    cdef void insert(self,int pos,Edge a):
        self.inner.insert(pos,a)
    cdef int index(self,Edge a):
        if a in self.inner:
            return self.inner.index(a)
        return -1
    cdef Edge get(self, int i):
        return <Edge> self.inner[i]
    cdef void sort(self):
        self.inner.sort(key = lambda c : c.Savings)
        #self.inner.sort()
    def __len__(self):
        return len(self.inner)

    def __richcmp__(Edge self, Edge other,int op):
        if op == 0:
            if self.inner.savings < other.inner.savings:
                return True
        return False

为了做到这一点,我在类中创建了方法sort,但是当我执行它时,我收到以下错误消息:

  

例外属性错误:&#34;&#39; fib.Edge&#39;对象没有属性&#39;储蓄&#39;&#34; in&#39; fib.Alist.sort&#39;忽略

1 个答案:

答案 0 :(得分:0)

这里出了什么问题

Python-lambda函数无法访问Edge的cdef属性。如果您尝试从python直接访问cdef类的属性,除非您添加readonly(用于读取访问)或public(用于读取和写入访问),否则将收到错误属性定义。

以此Edge类为例:

cdef class Edge:
    cdef readonly int savings # visible from python
    cdef int foo # not visible from python

    def __init__(self, int s):
        self.savings = s
        self.foo = 42

    def __repr__(self):
        """Friendly representation so we can see how the edges sort."""
        return "Edge: {}".format(self.savings)

如果我们编译它(假设它驻留在文件sortlist.pyx中)并将其导入Python shell:

In [1]: import sortlist as sl

In [2]: e = sl.Edge(42)

In [3]: e.savings
Out[3]: 23

In [4]: e.foo
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-3ebfe6d526e9> in <module>()
----> 1 e.foo

AttributeError: 'sortlist.Edge' object has no attribute 'foo'

如果您访问readonly属性saving,一切正常,但仅Cython属性foo会引发您获得的错误。并不是属性不存在,Python就是看不到它。

工作示例

基本上,修复方法是:将readonly添加到Edge类中的节省声明中。上面的Edge类使用以下代码。

cdef class Alist:
    cdef list inner

    def __init__(self):
        self.inner = []

    cdef void append(self, Edge a):
        self.inner.append(a)

    cdef void sort(self):
        self.inner.sort(key = lambda c : c.savings)

def test_sorting():
    # create edges with saving between 0 an 9
    edges = [Edge(i) for i in range(10)]
    # create an intersting instance for sorting
    shuffle(edges)
    al = Alist()
    # fill the inner list
    for e in edges:
        al.append(e)
    print("Finished Alist:", al.inner)
    al.sort()
    print("Sorted Alist:", al.inner)

为什么你可能不需要 richcmp (现在的位置)

__richcmp__中定义Alist方法时,它可用于比较两个Alist个对象。因此,键入Edge作为此处没有用。

您可以为richcmp定义Edge方法,这意味着可以用来比较两个Edge对象的方法。我强烈建议实施所有比较。因为它现在可能会显示一些奇怪的行为,如

In [1]: e1 = Edge(42)

In [2]: e2 = Edge(42)

In [3]: e3 = Edge(23)

In [4]: e1 < e2
Out[4]: False
# How it is supposed to be

In [5]: e1 == e2
Out[5]: False 
# This should be True

In [6]: e1 < e3
Out[6]: True
# How it is supposed to be

In [6]: e1 <= e3
Out[6]: False
# This should be True

因为所有非op=0的{​​{1}}操作(也称为<)的比较默认为False。因此,如果您想使用它,请一直使用。

有关丰富比较的更多详细信息,请参见here