[Python-ideas] Modern language design survey for "assign and compare" statements

Terry Reedy tjreedy at udel.edu
Mon May 21 13:00:51 EDT 2018

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 
>> <rhodri at 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:

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

More information about the Python-ideas mailing list