簡體   English   中英

按cdef類中的屬性對cdef對象列表進行排序

[英]Sort a list of cdef objects by attribute in a cdef class

我想對這個類的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 ,但是當我執行它時,我獲得以下錯誤消息:

異常AttributeError:''fib.Edge'對象在'fib.Alist.sort'中沒有屬性'Saving'“被忽略

這里出了什么問題

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作為此處沒有用。

您可以做的是為Edge定義richcmp方法,這意味着可以用於比較兩個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比較,即< operation(也可用作cpython.object.Py_LT ),默認為False。 因此,如果您想使用它,請一直使用。

有關豐富比較的更多詳細信息,請參見此處

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM