Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does heapq push comparison work in 2.7 vs 3.x

import heapq

class Foo(object):
    def __init__(self, x):
        self._x = x

l = [Foo(1)]
heapq.heapify(l)
heapq.heappush(l, Foo(2))

This works in Python 2.7 but not in 3.x. As mentioned in the docs

In the future with Python 3, tuple comparison breaks for (priority, task) pairs if the priorities are equal and the tasks do not have a default comparison order.

How are non-comparable objects handled in 2.7's heapq.heappush?

like image 996
Alex Avatar asked Sep 15 '25 04:09

Alex


1 Answers

Let us assume that you want Foo instances to be compared by their ._x values. Your code may run in 2.x, but it will not work in any sensible fashion as Foo instancex will instead be compared by their ids. Python 3 protects you from such silent bugs by not having a useless default. heapq at least uses <. The following runs in 3.x and works correctly, at least for this example, in 2.x and 3.x.

import heapq

class Foo(object):
    def __init__(self, x):
        self._x = x
    def __repr__(self):
        return 'Foo(%s)' % self._x
    def __lt__(self, other):
        return self._x < other._x

l = [Foo(1)]
heapq.heapify(l)
heapq.heappush(l, Foo(2))
print(l)

Add other rich comparision methods as needed or desired. You could add if isinstance(other, Foo) else NotImplemented to the end of each return expression to make comparisons with non-Foo instances work better.

like image 58
Terry Jan Reedy Avatar answered Sep 17 '25 19:09

Terry Jan Reedy