
Steven D'Aprano wrote:
On Fri, 19 Jun 2009 07:02:12 am Terry Reedy wrote:
Backgound: Most functions that take an iterable as parameter iterate just once. Users of the function can pass any iterable, including iterators. The function will call iter(imput) and go.
If the user wants to iterate thru a virtual collection defined by an instance of an iterator class (built-in or user-defined) or generator function, the user must call the gf/ic with the appropriate arguments and pass the result.
I don't think it's an undue burden on the caller to construct their own iterator before calling your function.
Only if an iterator is not allowed. Nor do I think it an undue burden either to wrap the constructor, when appropriate, instead of calling it.
To summarise your idea (correct me if I'm wrong):
There are three ways of passing iterable-like arguments:
(A) pass a sequence object like lists;
(B) pass generators or iterators;
(C) pass a constructor which returns a generator or iterator, plus appropriate arguments.
Right.
Insider your function, you can easily iterate over (A) or (C) multiple times, but not (B).
I don't think there's any way to treat all three cases identically. Your proposed gfic class will allow you to treat case (C) just like (A),
That is precisely the point.
at the cost of expecting the caller to call gfic() rather than pass a constructor directly.
See above
But the caller still can't pass an iterator in place of a sequence or constructor, so you haven't solved anything, merely shifted the burden on the user from calling one of:
function(list(constructor(*args, **kwargs))) function(list(iterator))
to calling one of:
function(gfic(constructor, *args, **kwargs)) function(list(iterator))
Right. I consider list-avoidance a good thing, more so, it appears than you ;-).
As I see it, the correct solution for "my function needs to iterate over an iterable twice" is not to expect the caller to pass a sequence, but to convert the iterable to a sequence inside your function:
def function(iterable): # Iterate over iterable twice L = list(iterable) for _ in (1, 2): for x in L: pass
Apart from needing to knowing to avoid non-terminating iterators, the user need not know whether you walk the input once or twice.
I suppose there is some benefit when dealing with huge iterators, but that's probably best dealt with on an ad hoc basis by requiring the user to pass a constructor directly.
Thank you for your response and analysis. tjr