Python sort with key implementation

时间:2019-05-17 08:23:28

标签: python sorting

I was experimenting with python sorting using key. I'm interested in the inner working of the algorithm. Is it roughly equivalent to Schwartzian transform (Decorate-Sort-Undecorate)触发不同的过滤器?

特别是:

  • 规格密钥仅提取一次。可以假设这发生在比较之前吗?
  • 提取的密钥如何保存在内存中?作为元组(key, orginal_value)还是使用其他方法。

我使用了以下测试程序

class Isbn:
    def __init__(self, isbn_num):
        self.isbn_num = isbn_num

    def __lt__(self, other):
        print(f"__lt__ {self.isbn_num} {other.isbn_num}")
        return self.isbn_num < other.isbn_num

    def __repr__(self) -> str:
        return f'Isbn({self.isbn_num})'


class Book:
    def __init__(self, isbn):
        self.isbn = Isbn(isbn)

    def __repr__(self) -> str:
        return f'Book({self.isbn})'

    @property
    def key(self):
        print(f"key {self.isbn}")
        return self.isbn


books = [Book(5), Book(10), Book(6), Book(2)]
books.sort(key=lambda b: b.key)
print(books)

哪个给出以下输出:

key Isbn(5)
key Isbn(10)
key Isbn(6)
key Isbn(2)
__lt__ 10 5
__lt__ 6 10
__lt__ 6 10
__lt__ 6 5
__lt__ 2 6
__lt__ 2 5
[Book(Isbn(2)), Book(Isbn(5)), Book(Isbn(6)), Book(Isbn(10))]

2 个答案:

答案 0 :(得分:1)

是的,在某些情况下,Python确实使用了Schwartzian transform。 来自this documentation

  

Python程序员在比较操作可能比较昂贵的情况下使用转换。

答案 1 :(得分:1)

专门讨论CPython(可使用其他Python实现):

它确实进行转换。当前,它在开始排序之前会构建一个C键数组。这完全是用C语言完成的-因此它不是Python列表。不涉及Python元组。

这是摘自listobject.c的(当前)相关C代码的摘录(当然,这会随着CPython的发展而改变)。

key_func是关键功能。 saved_ob_size是列表的长度。 saved_ob_item是原始列表中的数组。

2239 if (keyfunc == NULL) { 
         ...
2243     } 
2244     else { 
         ...    
2256         for (i = 0; i < saved_ob_size ; i++) { 
2257             keys[i] = PyObject_CallFunctionObjArgs(keyfunc, saved_ob_item[i], 
2258                                                    NULL); 
                 ...
2265             } 
2266         }