代码之家  ›  专栏  ›  技术社区  ›  Lesiak

带键实现的Python排序

  •  1
  • Lesiak  · 技术社区  · 6 年前

    我对算法的内部工作很感兴趣。 它大致等价于施瓦茨变换吗 (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))]
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   strubbly    6 年前

    具体谈到CPython(还有其他Python实现):

    它确实做了转换。它当前在开始排序之前构建一个键的C数组。这完全是用C语言完成的,所以它不是Python列表。不涉及Python元组。

    listobject.c .

    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         } 
    
        2
  •  1
  •   funie200 gxyd    6 年前

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

    Python程序员在比较操作可能很昂贵的地方使用转换。