I'm trying to use queue.PriorityQueue
in Python 3(.6).
I would like to store objects with a given priority. But if two objects have the same priority, I don't mind PriorityQueue.get
to return either. In other words, my objects can't be compared at integers, it won't make sense to allow them to be, I just care about the priority.
In Python 3.7's documentation, there's a solution involving dataclasses
. And I quote:
If the data elements are not comparable, the data can be wrapped in a class that ignores the data item and only compares the priority number:
from dataclasses import dataclass, field
from typing import Any
@dataclass(order=True)
class PrioritizedItem:
priority: int
item: Any=field(compare=False)
Alas, I'm using Python 3.6. In the documentation of this version of Python, there's no comment on using PriorityQueue
for the priorities, not bothering about the "object value" which wouldn't be logical in my case.
Is there a better way than to define __le__
and other comparison methods on my custom class? I find this solution particularly ugly and counter-intuitive, but that might be me.
dataclasses
is just a convenience method to avoid having to create a lot of boilerplate code.
You don't actually have to create a class. A tuple with a unique counter value too:
from itertools import count
unique = count()
q.put((priority, next(unique), item))
so that ties between equal priority are broken by the integer that follows; because it is always unique the item
value is never consulted.
You can also create a class using straight-up rich comparison methods, made simpler with @functools.total_ordering
:
from functools import total_ordering
@total_ordering
class PrioritizedItem:
def __init__(self, priority, item):
self.priority = priority
self.item = item
def __eq__(self, other):
if not isinstance(other, __class__):
return NotImplemented
return self.priority == other.priority
def __lt__(self, other):
if not isinstance(other, __class__):
return NotImplemented
return self.priority < other.priority