I'm writing a few simple functions that compare the length of an iterator to an integer, returning as early as possible. Right now I have:
class ILengthComparator:
def __init__(self, iterator: Iterator):
self.iterator = iterator
def has_more(self) -> bool:
try:
next(self.iterator)
except StopIteration:
return False
return True
def __eq__(self, length: int) -> bool:
if length < 0:
return False
if not self.has_more():
return length == 0
return self == length-1
def __gt__(self, length: int) -> bool:
if length < 1:
return False
if not self.has_more():
return True
return self > length-1
def __lt__(self, length: int) -> bool:
if length < 0:
return True
if not self.has_more():
return False
return self < length - 1
Clearly this class isn't finished (__neq__
, __gte__
, __lte__
), and anything after the first comparison isn't guaranteed to work (as the iterator may be consumed), but I'm wondering: is it is possible to logically simplify this into a single function with an operator function as an argument (ie operator.eq
, operator.lt
), or at least just reduce the semi-duplicate parts (ie, every function has a comparison with length
against a number, and a case for checking if the iterator is empty - each with a rather ad-hoc return value).
(any suggestions don't need to be recursive or use the has_more
method, those were just the first thing I reached for when trying to solve this problem)
Pastebin with the above some quick and dirty unit tests: https://pastebin.com/N65Q2qcJ
__eq__
and__lt__
to determine__gt__
, by the time__lt__
was called,__eq__
would have already consumed the iterator. \$\endgroup\$ – Chris Real Jan 14 '20 at 1:06.tee()
often isn't a good idea, because it has to store the results of eachnext()
call for _re_iteration (which can consume a decent amount of memory depending on what the iterator is iterating over). Even if not for this specific use case, it still seems like a pretty awesome decorator! \$\endgroup\$ – Chris Real Jan 14 '20 at 4:50