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

2024-04-19 22:24:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我想对这个类的列表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,但在执行该方法时,得到以下错误消息:

Exception AttributeError: "'fib.Edge' object has no attribute 'savings'" in 'fib.Alist.sort' ignored


Tags: self列表returnif排序defsortint
1条回答
网友
1楼 · 发布于 2024-04-19 22:24:32

这里出什么问题了

Python-lambda函数无法访问Edge的cdef属性。如果您试图从python直接访问cdef类的属性,您将得到一个错误,除非您将readonly(用于读访问)或public(用于读写访问)添加到属性定义中。你知道吗

以这个边缘类为例:

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 only属性foo抛出您得到的错误。不是属性不在那里,Python就是看不到它。你知道吗

工作示例

基本上,修复方法是:将readonly添加到Edge类中的savings声明中。上面的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(现在的位置)

Alist中定义__richcmp__方法时,可以使用它来比较两个Alist对象。因此,键入as 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的比较都默认为False,这是<操作(也可用作cpython.object.Py_LT)。所以如果你想用这个,就一直用。你知道吗

关于丰富比较的更多细节可以在here中找到。你知道吗

相关问题 更多 >