Expose `itertools.count.start` and implement `itertools.count.__eq__` based on it, like `range`.

I suggest exposing `itertools.count.start` and implementing `itertools.count.__eq__` based on it. This'll provide the same benefits that `range` got by exposing `range.start` and allowing `range.__eq__`.

Now that I think about it, I would ideally want `itertools.count` to be deprecated in favor of `range(float('inf'))`, but I know that would never happen.
On Thursday, May 15, 2014 11:02:56 PM UTC+3, Ram Rachum wrote:
I suggest exposing `itertools.count.start` and implementing `itertools.count.__eq__` based on it. This'll provide the same benefits that `range` got by exposing `range.start` and allowing `range.__eq__`.

On 5/15/2014 4:02 PM, Ram Rachum wrote:
I suggest exposing `itertools.count.start` and implementing `itertools.count.__eq__` based on it. This'll provide the same benefits that `range` got by exposing `range.start` and allowing `range.__eq__`.
The benefits cannot be the same because range and count are in different categories.
A range object is an immutable, constant attribute, reiterable sequence object. It makes sense to expose the read-only constants and compare on the basis of them. This is as sensible as comparing other sequences.
A count is an iterator. We do not try to compare iterators (except by identity). The start value is only the initial value yielded. As soon as values are pulled from the iterator, the starting value is history. The generator equivalent in the doc can be condensed a bit to how I would actually write it.
def count(start=0, step=1): while True: yield start start += step
For an iterator class, I would save the start parameter as self.n, .count, or .current. In other words, something equivlaent to
def __init__(self, start=0, step=1): self.count = start self.step = step
If you want an augmented iterator class, you should write one yourself for your specific needs.

On Thu, May 15, 2014 at 01:02:56PM -0700, Ram Rachum wrote:
I suggest exposing `itertools.count.start` and implementing `itertools.count.__eq__` based on it. This'll provide the same benefits that `range` got by exposing `range.start` and allowing `range.__eq__`.
What benefits are those? Under what circumstances have you compared two range objects or checked their start? That's a serious question -- I don't recall ever wanting to compare range objects for equality.
The iterator protocol is intentionally very simple, and I think that is a good thing. Adding complexity to one specific standard iterator without a good, solid use-case does not strike me as a good idea. But even if you have a good use-case, I don't think the concept of equality for count objects is very well defined. Consider:
from itertools import count a = count(1) b = count(1) _ = next(b); _ = next(b) c = count(3)
a.start and b.start are the same, so one might argue that a and b should compare equal. But next(a) and next(b) are different, so one might equally argue that a and b should compare unequal.
Likewise b.start and c.start are different, but next(b) and next(c) return the same value, so one might expect b and c to be both equal and unequal.
I think, whichever definition of equality you pick, people will be surprised by it fifty percent of the time.
participants (3)
-
Ram Rachum
-
Steven D'Aprano
-
Terry Reedy