On 5/21/2018 9:14 AM, Rhodri James wrote:
On 21/05/18 12:29, Daniel Moisset wrote:

On 21 May 2018 at 12:05, Rhodri James <rho...@kynesim.co.uk> wrote:
with my usual use cases.  What I normally want is the Python equivalent of:

   while ((v = get_something()) != INCONVENIENT_SENTINEL)
     do_something(v);

That use case should be covered by

for v in iter(get_something, INCOVENIENT_SENTINEL):
     do_something(v)

There are many ways round my use case, all of them inelegant.  That has to be one of the less comprehensible alternatives.

The following might be slightly clearer.

item_iterator = iter(get_something, INCONVENIENT_SENTINEL)
for item in item_iterator:
    do_something(item)

I think iter is the right thing to use here. I think your contrary response is a least partly due to unfamiliarity with the two-argument form of iter and how it abbreviates and encapsulates the alternatives you already know.

The essential idea of 'iter' is to produce iterators from Python objects. When the input is a function, sentinel pair, iter returns an instance of a internal callable_iterator class, equivalent to

class callable_iterator
    def __init__(self, function, sentinel)
        self.function = function
        self.sentinel = sentinel
    def __iter__(self):
        return self
    def __next__(self):
        item = self.function()
        if item == self.sentinel:
            raise StopIteration
        return item

If iter were actually written in Python, it might instead return the generator returned by a generator function encapsulating one of well-know while loop idioms.

# Double call form.
def function_sentinel(function, sentinel)
    item = function()
    while item != sentinel
        yield item
        item = function()

# Loop and a half form; the loop body is essentially the same
# as the body of callable_iterator.__next__, above
def function_sentinel(function, sentinel):
    while True:
        item = function()      # No 'self.'
        if item == sentinel:   # No 'self.'
            break              # Instead of 'raise StopIteration
        yield item             # Instead of 'return item'

The essential idea of for-loops is to cleanly separate sequential production of items to be processed, in the header, from processing of each item, in the body. It always calls iter(iterable) for you. If you need to pass two arguments to iter, you must do it explicitly. The while alternatives for this case intermix getting and processing items in the body.

--
Terry Jan Reedy


_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to