代码之家  ›  专栏  ›  技术社区  ›  Abhijit Sarkar

为什么sort忽略了类中定义的总排序方法?

  •  0
  • Abhijit Sarkar  · 技术社区  · 1 年前

    给定以下类别:

    @functools.total_ordering
    class Entry:
        def __init__(self, nr: list[int, int] = None, p: int = 0) -> None:
            self.nr = nr if nr is not None else [0, 0]
            self.p = p
    
        def __repr__(self) -> str:
            return f"Entry(nr={self.nr}, p={self.p})"
    
        def __eq__(self, other: Entry) -> bool:
            return (self.nr[0] == other.nr[0] and self.nr[1] >= other.nr[1]) or (self.nr[0] > other.nr[0])
    
        def __gt__(self, other: Entry) -> bool:
            return (self.nr[0] == other.nr[0] and self.nr[1] < other.nr[1]) or (self.nr[0] < other.nr[0])
    

    以及条目列表:

    L = [
        Entry(nr=[98, 111], p=0),
        Entry(nr=[111, 98], p=1), 
        Entry(nr=[98, 111], p=2), 
        Entry(nr=[111, 99], p=3), 
        Entry(nr=[99, 101], p=4), 
        Entry(nr=[101, 108], p=5), 
        Entry(nr=[108, -1], p=6)
    ]
    

    使命感 L.sort() 预计将产生以下订单(仅 p 为简洁起见所示的值): [0, 2, 4, 5, 6, 1, 3]

    但什么也没发生!为什么不呢?

    我还尝试过让这个班成为 dataclass 通过更换 __init__ 带有以下内容(并添加 数据类 当然,类的注释),但这并没有改变任何事情。我更喜欢它 数据类 ,因此,我不必提供 __repr__

    nr: list[int, int] = dataclasses.field(default_factory=lambda: [0, 0])
    p: int = 0
    
    1 回复  |  直到 1 年前
        1
  •  2
  •   Samwise    1 年前

    据我所知,这只是比较器方法中的一个逻辑错误——请注意 __eq__ 是的 == __gt__ 是的 <

    你的 __当量__ 实现得更像 <= 运算符,这意味着它没有测试任何传统意义上的相等性,而且实际上是不可交换的,您应该期望它会产生一些奇怪的行为(包括类似 sort 不做任何事情,因为它认为所有项目都是等效的)。

    如果你只是这样做:

        def __eq__(self, other: 'Entry') -> bool:
            return (self.nr == other.nr)
    
        def __gt__(self, other: 'Entry') -> bool:
            return (self.nr > other.nr)
    

    然后 __当量__ 具有更有用的行为, functools.total_ordering 能够填充其余的方法,并且您可以得到您想要的排序行为。