Re: writable iterators?

2011-06-23 Thread Thomas 'PointedEars' Lahn
[Sorry for over-quoting, I am not sure how to trim this properly]

Steven D'Aprano wrote:

 On Thu, 23 Jun 2011 09:30 am Thomas 'PointedEars' Lahn wrote:
 Mel wrote:
 Steven D'Aprano wrote:
 I *guess* that what you mean by writable iterators is that rebinding
 e should change seq in place, i.e. you would expect that seq should now
 equal [42, 42]. Is that what you mean? It's not clear.
 
 Fortunately, that's not how it works, and far from being a
 limitation, it would be *disastrous* if iterables worked that way. I
 can't imagine how many bugs would occur from people reassigning to the
 loop variable, forgetting that it had a side-effect of also reassigning
 to the iterable. Fortunately, Python is not that badly designed.
 
 And for an iterator like
 
 def things():
 yield 1
 yield 11
 yield 4
 yield 9
 
 I don't know what it could even mean.
 
 http://docs.python.org/reference/simple_stmts.html#the-yield-statement
 
 You could have tried to debug.
 
 I think you have missed the point of Mel's comment. He knows what the
 yield statement does. He doesn't know what it would mean to write to an
 iterator like things().
 
 Neither do I.

AIUI the OP is referring to write accesses to the iteration variable
(for want of a better term), not being aware what iterators are.

-- 
PointedEars

Bitte keine Kopien per E-Mail. / Please do not Cc: me.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-23 Thread Ian Kelly
On Wed, Jun 22, 2011 at 3:54 PM, Steven D'Aprano
steve+comp.lang.pyt...@pearwood.info wrote:
 Fortunately, that's not how it works, and far from being a limitation,
 it would be *disastrous* if iterables worked that way. I can't imagine
 how many bugs would occur from people reassigning to the loop variable,
 forgetting that it had a side-effect of also reassigning to the iterable.
 Fortunately, Python is not that badly designed.

The example syntax is a non-starter, but there's nothing wrong with
the basic idea.  The STL of C++ uses output iterators and a quick
Google search doesn't turn up any harmful-style rants about those.

Of course, there are a couple of major differences between C++
iterators and Python iterators.  FIrst, C++ iterators have an explicit
dereference step, which keeps the iterator variable separate from the
value that it accesses and also provides a possible target for
assignment.  You could say that next(iterator) is the corresponding
dereference step in Python, but it is not accessible in a for loop and
it does not provide an assignment target in any case.

Second, C++ iterators separate out the dereference step from the
iterator advancement step.  In Python, both next(iterator) and
generator.send() are expected to advance the iterator, which would be
problematic for creating an iterator that does both input and output.

I don't think that output iterators would be a disaster in Python,
but I also don't see a clean way to add them to the existing iterator
protocol.

 If you want to change the source iterable, you have to explicitly do so.
 Whether you can or not depends on the source:

 * iterators are lazy sequences, and cannot be changed because there's
 nothing to change (they don't store their values anywhere, but calculate
 them one by one on demand and then immediately forget that value);

No, an iterator is an object that allows traversal over a collection
in a manner independent of the implementation of that collection.  In
many instances, especially in Python and similar languages, the
collection is abstracted to an operation over another collection, or
even to the results of a serial computation where there is no actual
collection in memory.

Iterators are not lazy sequences, because they do not behave like
sequences.  You can't index them, you can't reiterate them, you can't
get their length (and before you point out that there are ways of
doing each of these things -- yes, but none of those ways use
sequence-like syntax).  For true lazy sequences, consider the concept
of streams and promises in the functional languages.

In any case, the desired behavior of an output iterator on a source
iterator is clear enough to me.  If the source iterator is also an
output iterator, then it propagates the write to it.  If the source
iterator is not an output iterator, then it raises a TypeError.

 * mutable sequences like lists can be changed. The standard idiom for
 that is to use enumerate:

 for i, e in enumerate(seq):
    seq[i] = e + 42

Unless the underlying collection is a dict, in which case I need to do:

for k, v in d.items():
d[k] = v + 42

Or a file:

for line in f:
# I'm not even sure whether this actually works.
f.seek(-len(line))
f.write(line.upper())

As I said above, iterators are supposed to provide
implementation-independent traversal over a collection.  For writing,
enumerate fails in this regard.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-23 Thread Neal Becker
Ian Kelly wrote:

 On Wed, Jun 22, 2011 at 3:54 PM, Steven D'Aprano
 steve+comp.lang.pyt...@pearwood.info wrote:
 Fortunately, that's not how it works, and far from being a limitation,
 it would be *disastrous* if iterables worked that way. I can't imagine
 how many bugs would occur from people reassigning to the loop variable,
 forgetting that it had a side-effect of also reassigning to the iterable.
 Fortunately, Python is not that badly designed.
 
 The example syntax is a non-starter, but there's nothing wrong with
 the basic idea.  The STL of C++ uses output iterators and a quick
 Google search doesn't turn up any harmful-style rants about those.
 
 Of course, there are a couple of major differences between C++
 iterators and Python iterators.  FIrst, C++ iterators have an explicit
 dereference step, which keeps the iterator variable separate from the
 value that it accesses and also provides a possible target for
 assignment.  You could say that next(iterator) is the corresponding
 dereference step in Python, but it is not accessible in a for loop and
 it does not provide an assignment target in any case.
 
 Second, C++ iterators separate out the dereference step from the
 iterator advancement step.  In Python, both next(iterator) and
 generator.send() are expected to advance the iterator, which would be
 problematic for creating an iterator that does both input and output.
 
 I don't think that output iterators would be a disaster in Python,
 but I also don't see a clean way to add them to the existing iterator
 protocol.
 
 If you want to change the source iterable, you have to explicitly do so.
 Whether you can or not depends on the source:

 * iterators are lazy sequences, and cannot be changed because there's
 nothing to change (they don't store their values anywhere, but calculate
 them one by one on demand and then immediately forget that value);
 
 No, an iterator is an object that allows traversal over a collection
 in a manner independent of the implementation of that collection.  In
 many instances, especially in Python and similar languages, the
 collection is abstracted to an operation over another collection, or
 even to the results of a serial computation where there is no actual
 collection in memory.
 
 Iterators are not lazy sequences, because they do not behave like
 sequences.  You can't index them, you can't reiterate them, you can't
 get their length (and before you point out that there are ways of
 doing each of these things -- yes, but none of those ways use
 sequence-like syntax).  For true lazy sequences, consider the concept
 of streams and promises in the functional languages.
 
 In any case, the desired behavior of an output iterator on a source
 iterator is clear enough to me.  If the source iterator is also an
 output iterator, then it propagates the write to it.  If the source
 iterator is not an output iterator, then it raises a TypeError.
 
 * mutable sequences like lists can be changed. The standard idiom for
 that is to use enumerate:

 for i, e in enumerate(seq):
 seq[i] = e + 42
 
 Unless the underlying collection is a dict, in which case I need to do:
 
 for k, v in d.items():
 d[k] = v + 42
 
 Or a file:
 
 for line in f:
 # I'm not even sure whether this actually works.
 f.seek(-len(line))
 f.write(line.upper())
 
 As I said above, iterators are supposed to provide
 implementation-independent traversal over a collection.  For writing,
 enumerate fails in this regard.


While python may not have output iterators, interestingly numpy has just added 
this capability.  It is part of nditer.  So, this may suggest a syntax.

There have been a number of responses to my question that suggest using 
indexing 
(maybe with enumerate).  Once again, this is not suitable for many data 
structures.  c++ and stl teach that iteration is often far more efficient than 
indexing.  Think of a linked-list.  Even for a dense multi-dim array, index 
calculations are much slower than iteration.

I believe the lack of output iterators is a defienciency in the python iterator 
concept.


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-23 Thread Chris Torek
(I apologize for the length of this article -- if I had more time,
I could write something shorter...)

In article mailman.296.1308770918.1164.python-l...@python.org
Neal Becker  ndbeck...@gmail.com wrote:
AFAICT, the python iterator concept only supports readable iterators,
not write.  
Is this true?

for example:

for e in sequence:
  do something that reads e
  e = blah # will do nothing

I believe this is not a limitation on the for loop, but a limitation on the 
python iterator concept.  Is this correct?

Yes.

Having read through the subsequent discussion, I think in some ways
you have run into some of the same issues that I did in my originally
somewhat-vague thoughts on exceptions, in that your example is too
close to real Python code and led a number of followers (including
me, originally) astray. :-)

It might be better expressed as, say:

for i in IndirectIter(sequence):
current_value = i.get()
result = compute(current_value)
i.set(result)

which is clearly rather klunky, and also does not fit super-well
into existing iter protocols, but could be implemented for lists
and dictionaries for instance; see below.

A more direct syntax (which I admit is pretty klunky, this is
kind of off the top of my head):

for item in sequence with newvalue:
newvalue = compute(item)

This leaves unresolved the issue of what if you don't set the
variable newvalue, but perhaps the for loop could internally
bind both item *and* newvalue at the top of each iteration,
so that this is essentially:

for item in sequence with newvalue:
newvalue = item # automatically inserted for you
... user code; if it doesn't set newvalue the .set()
(or whatever equivalent) will re-save the original value ...

Or -- and I think this is actually a better idea -- perhaps it
could pre-bind newvalue = None and the automatic iter.set()
invocation would leave None undisturbed.  In which case, the
internal implementation could even use .set() only, rather than
having to call iter.next(), as the primary protocol, with iter.set()
changing the current value and then doing, in essence, return
iter.next().  Of course this is just a micro-optimization that
might only apply to CPython in the first place; I am getting way
ahead of myself here. :-)

(To expand, what I am thinking at the moment is that if one had
this syntax, one would change the iter protocol.  An iterator object
would still provide __iter__ and next callables always.  If it
also provides a set callable -- or setitem or something like
that; the name is clearly flexible at this point -- then this would
make it a writeable iterator that one could use with the new
syntax.  The protocol would become:

for var1 in container [with var2]:
code

which if the with is present would mean: call container.__iter__
to get an iterable as usual, with the usual check that iter.__iter__
is also a callable.  Then, though, check the iterable for the *new*
callable as well.  If not present, you get an error.  If present,
call iter.next() initially and bind var2 to None.  At the bottom
of the loop, to step the loop, call the iter's iter.set() with
var2; bind its return value to var1, and re-bind var2 to None again.
Both iter.next() and iter.set() can raise StopIteration to terminate
the loop.)

This idea needs more thought applied, of course.

Another possible syntax:

for item in container with key:

which translates roughly to bind both key and item to the value
for lists, but bind key to the key and value for the value for
dictionary-ish items.  Then instead of:

for elem in sequence:
...
elem = newvalue

the OP would write, e.g.:

for elem in sequence with index:
...
sequence[index] = newvalue

which of course calls the usual container.__setitem__.  In this
case the new protocol is to have iterators define a function
that returns not just the next value in the sequence, but also
an appropriate key argument to __setitem__.  For lists, this
is just the index; for dictionaries, it is the key; for other
containers, it is whatever they use for their keys.

I actually think I like this second syntax more, as it leaves the
container-modifying step explicitly spelled out in user code.  It
would also eliminate much of the need for enumerate().

 example IndirectIter below 

class IndirectIterError(TypeError):
pass

class _IInner(object):
def __init__(self, outer, iterlist):
self.outer = outer
self.iterlist = iterlist
self.index = -1

def __iter__(self):
return self

def next(self):
self.index += 1
if self.index = len(self.iterlist):
raise StopIteration
return self

def get(self):
return self.outer._get(self.index, self.iterlist)

def set(self, newvalue):
return self.outer._set(self.index, self.iterlist, newvalue)

class IndirectIter(object):
def __init__(self, 

Re: writable iterators?

2011-06-23 Thread Chris Torek
In article iu00fs1...@news3.newsguy.com I wrote, in part:
Another possible syntax:

for item in container with key:

which translates roughly to bind both key and item to the value
for lists, but bind key to the key and value for the value for
dictionary-ish items.  Then ... the OP would write, e.g.:

for elem in sequence with index:
...
sequence[index] = newvalue

which of course calls the usual container.__setitem__.  In this
case the new protocol is to have iterators define a function
that returns not just the next value in the sequence, but also
an appropriate key argument to __setitem__.  For lists, this
is just the index; for dictionaries, it is the key; for other
containers, it is whatever they use for their keys.

I note I seem to have switched halfway through thinking about
this from value to index for lists, and not written that. :-)

Here's a sample of a simple generator that does the trick for
list, buffer, and dict:

def indexed_seq(seq):

produce a pair
key_or_index value
such that seq[key_or_index] is value initially; you can
write on seq[key_or_index] to set a new value while this
operates.  Note that we don't allow tuple and string here
since they are not writeable.

if isinstance(seq, (list, buffer)):
for i, v in enumerate(seq):
yield i, v
elif isinstance(seq, dict):
for k in seq:
yield k, seq[k]
else:
raise TypeError(don't know how to index %s % type(seq))

which shows that there is no need for a new syntax.  (Turning the
above into an iterator, and handling container classes that have
an __iter__ callable that produces an iterator that defines an
appropriate index-and-value-getter, is left as an exercise. :-) )
-- 
In-Real-Life: Chris Torek, Wind River Systems
Intel require I note that my opinions are not those of WRS or Intel
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W)  +1 801 277 2603
email: gmail (figure it out)  http://web.torek.net/torek/index.html
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-23 Thread Neal Becker
Chris Torek wrote:

 In article iu00fs1...@news3.newsguy.com I wrote, in part:
Another possible syntax:

for item in container with key:

which translates roughly to bind both key and item to the value
for lists, but bind key to the key and value for the value for
dictionary-ish items.  Then ... the OP would write, e.g.:

for elem in sequence with index:
...
sequence[index] = newvalue

which of course calls the usual container.__setitem__.  In this
case the new protocol is to have iterators define a function
that returns not just the next value in the sequence, but also
an appropriate key argument to __setitem__.  For lists, this
is just the index; for dictionaries, it is the key; for other
containers, it is whatever they use for their keys.
 
 I note I seem to have switched halfway through thinking about
 this from value to index for lists, and not written that. :-)
 
 Here's a sample of a simple generator that does the trick for
 list, buffer, and dict:
 
 def indexed_seq(seq):
 
 produce a pair
 key_or_index value
 such that seq[key_or_index] is value initially; you can
 write on seq[key_or_index] to set a new value while this
 operates.  Note that we don't allow tuple and string here
 since they are not writeable.
 
 if isinstance(seq, (list, buffer)):
 for i, v in enumerate(seq):
 yield i, v
 elif isinstance(seq, dict):
 for k in seq:
 yield k, seq[k]
 else:
 raise TypeError(don't know how to index %s % type(seq))
 
 which shows that there is no need for a new syntax.  (Turning the
 above into an iterator, and handling container classes that have
 an __iter__ callable that produces an iterator that defines an
 appropriate index-and-value-getter, is left as an exercise. :-) )

Here is what numpy nditer does:

 for item in np.nditer(u, [], ['readwrite'], order='C'):
... item[...] = 10

Notice that the slice syntax is used to 'dereference' the iterator.  This seems 
like reasonably pythonic syntax, to my eye.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-23 Thread Dan Stromberg
On Wed, Jun 22, 2011 at 12:28 PM, Neal Becker ndbeck...@gmail.com wrote:

 AFAICT, the python iterator concept only supports readable iterators, not
 write.
 Is this true?

 for example:

 for e in sequence:
  do something that reads e
  e = blah # will do nothing

 I believe this is not a limitation on the for loop, but a limitation on the
 python iterator concept.  Is this correct?


The Generators, Iterators and Comprehensions 2011 document at the URL below
covers a way of doing this.

http://stromberg.dnsalias.org/~dstromberg/Intro-to-Python/
-- 
http://mail.python.org/mailman/listinfo/python-list


writable iterators?

2011-06-22 Thread Neal Becker
AFAICT, the python iterator concept only supports readable iterators, not 
write.  
Is this true?

for example:

for e in sequence:
  do something that reads e
  e = blah # will do nothing

I believe this is not a limitation on the for loop, but a limitation on the 
python iterator concept.  Is this correct?

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread Ethan Furman

Neal Becker wrote:
AFAICT, the python iterator concept only supports readable iterators, not write.  
Is this true?


for example:

for e in sequence:
  do something that reads e
  e = blah # will do nothing

I believe this is not a limitation on the for loop, but a limitation on the 
python iterator concept.  Is this correct?


No.  e = blah will rebind the indentifier 'e' with 'blah' whatever that 
is.  That is how python works.


Now, if e is mutable, say a list, you can do

   e.append(blah)

and, since the name 'e' is not being rebound, you would see the change 
in 'sequence'.


~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread Benjamin Kaplan
On Jun 22, 2011 12:31 PM, Neal Becker ndbeck...@gmail.com wrote:

 AFAICT, the python iterator concept only supports readable iterators, not
write.
 Is this true?

 for example:

 for e in sequence:
  do something that reads e
  e = blah # will do nothing

 I believe this is not a limitation on the for loop, but a limitation on
the
 python iterator concept.  Is this correct?

consider the following code

x = [1,2,3]
y = x[0]
y = 5

Would you expect x to be [5,2,3] now? Assignment in python assigns a name to
an object. It doesn't change the value of a variable.

If you have a generator, you can use send() to put data in you need the
actual generator itself to do that.


 --
 http://mail.python.org/mailman/listinfo/python-list
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread Steven D'Aprano
On Wed, 22 Jun 2011 15:28:23 -0400, Neal Becker wrote:

 AFAICT, the python iterator concept only supports readable iterators,
 not write. Is this true?
 
 for example:
 
 for e in sequence:
   do something that reads e
   e = blah # will do nothing
 
 I believe this is not a limitation on the for loop, but a limitation on
 the python iterator concept.  Is this correct?

Have you tried it? e = blah certainly does not do nothing, regardless 
of whether you are in a for loop or not. It binds the name e to the value 
blah.

 seq = [1, 2]
 for e in seq:
... print(e)
... e = 42
... print(e)
...
1
42
2
42


I *guess* that what you mean by writable iterators is that rebinding e 
should change seq in place, i.e. you would expect that seq should now 
equal [42, 42]. Is that what you mean? It's not clear.

Fortunately, that's not how it works, and far from being a limitation, 
it would be *disastrous* if iterables worked that way. I can't imagine 
how many bugs would occur from people reassigning to the loop variable, 
forgetting that it had a side-effect of also reassigning to the iterable. 
Fortunately, Python is not that badly designed.

If you want to change the source iterable, you have to explicitly do so. 
Whether you can or not depends on the source:

* iterators are lazy sequences, and cannot be changed because there's 
nothing to change (they don't store their values anywhere, but calculate 
them one by one on demand and then immediately forget that value);

* immutable sequences, like tuples, are immutable and cannot be changed 
because that's what immutable means;

* mutable sequences like lists can be changed. The standard idiom for 
that is to use enumerate:

for i, e in enumerate(seq):
seq[i] = e + 42



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread Mel
Steven D'Aprano wrote:

 On Wed, 22 Jun 2011 15:28:23 -0400, Neal Becker wrote:
 
 AFAICT, the python iterator concept only supports readable iterators,
 not write. Is this true?
 
 for example:
 
 for e in sequence:
   do something that reads e
   e = blah # will do nothing
 
 I believe this is not a limitation on the for loop, but a limitation on
 the python iterator concept.  Is this correct?
 
 Have you tried it? e = blah certainly does not do nothing, regardless
 of whether you are in a for loop or not. It binds the name e to the value
 blah.
 
 seq = [1, 2]
 for e in seq:
 ... print(e)
 ... e = 42
 ... print(e)
 ...
 1
 42
 2
 42
 
 
 I *guess* that what you mean by writable iterators is that rebinding e
 should change seq in place, i.e. you would expect that seq should now
 equal [42, 42]. Is that what you mean? It's not clear.
 
 Fortunately, that's not how it works, and far from being a limitation,
 it would be *disastrous* if iterables worked that way. I can't imagine
 how many bugs would occur from people reassigning to the loop variable,
 forgetting that it had a side-effect of also reassigning to the iterable.
 Fortunately, Python is not that badly designed.

And for an iterator like

def things():
yield 1
yield 11
yield 4
yield 9

I don't know what it could even mean.

Mel.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread Neal Becker
Steven D'Aprano wrote:

 On Wed, 22 Jun 2011 15:28:23 -0400, Neal Becker wrote:
 
 AFAICT, the python iterator concept only supports readable iterators,
 not write. Is this true?
 
 for example:
 
 for e in sequence:
   do something that reads e
   e = blah # will do nothing
 
 I believe this is not a limitation on the for loop, but a limitation on
 the python iterator concept.  Is this correct?
 
 Have you tried it? e = blah certainly does not do nothing, regardless
 of whether you are in a for loop or not. It binds the name e to the value
 blah.
 

Yes, I understand that e = blah just rebinds e.  I did not mean this as an 
example of working code.  I meant to say, does Python have any idiom that 
allows 
iteration over a sequence such that the elements can be assigned?

...
 * iterators are lazy sequences, and cannot be changed because there's
 nothing to change (they don't store their values anywhere, but calculate
 them one by one on demand and then immediately forget that value);
 
 * immutable sequences, like tuples, are immutable and cannot be changed
 because that's what immutable means;
 
 * mutable sequences like lists can be changed. The standard idiom for
 that is to use enumerate:
 
 for i, e in enumerate(seq):
 seq[i] = e + 42
 
 
AFAIK, the above is the only python idiom that allows iteration over a sequence 
such that you can write to the sequence.  And THAT is the problem.  In many 
cases, indexing is much less efficient than iteration.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread Chris Kaynor
You could probably implement something like this using generators and the
send method (note the example is untested and intended for 2.6: I lack
Python on this machine):

def gen(list_):
  for i, v in enumerate(list_):
list_[i] = yield v

def execute():
  data = range(10)
  iterator = gen(data)
  lastValue = iterator.next()
  while True:
print lastValue
try:
  lastValue = iterator.send(lastValue + 1)
except StopIteration:
  break
  print data

 execute()
0
1
2
3
4
5
6
7
8
9
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]




Chris


On Wed, Jun 22, 2011 at 4:10 PM, Neal Becker ndbeck...@gmail.com wrote:

 Steven D'Aprano wrote:

  On Wed, 22 Jun 2011 15:28:23 -0400, Neal Becker wrote:
 
  AFAICT, the python iterator concept only supports readable iterators,
  not write. Is this true?
 
  for example:
 
  for e in sequence:
do something that reads e
e = blah # will do nothing
 
  I believe this is not a limitation on the for loop, but a limitation on
  the python iterator concept.  Is this correct?
 
  Have you tried it? e = blah certainly does not do nothing, regardless
  of whether you are in a for loop or not. It binds the name e to the value
  blah.
 

 Yes, I understand that e = blah just rebinds e.  I did not mean this as an
 example of working code.  I meant to say, does Python have any idiom that
 allows
 iteration over a sequence such that the elements can be assigned?

 ...
  * iterators are lazy sequences, and cannot be changed because there's
  nothing to change (they don't store their values anywhere, but calculate
  them one by one on demand and then immediately forget that value);
 
  * immutable sequences, like tuples, are immutable and cannot be changed
  because that's what immutable means;
 
  * mutable sequences like lists can be changed. The standard idiom for
  that is to use enumerate:
 
  for i, e in enumerate(seq):
  seq[i] = e + 42
 
 
 AFAIK, the above is the only python idiom that allows iteration over a
 sequence
 such that you can write to the sequence.  And THAT is the problem.  In many
 cases, indexing is much less efficient than iteration.

 --
 http://mail.python.org/mailman/listinfo/python-list

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread Thomas 'PointedEars' Lahn
Mel wrote:

 Steven D'Aprano wrote:
 I *guess* that what you mean by writable iterators is that rebinding e
 should change seq in place, i.e. you would expect that seq should now
 equal [42, 42]. Is that what you mean? It's not clear.
 
 Fortunately, that's not how it works, and far from being a limitation,
 it would be *disastrous* if iterables worked that way. I can't imagine
 how many bugs would occur from people reassigning to the loop variable,
 forgetting that it had a side-effect of also reassigning to the iterable.
 Fortunately, Python is not that badly designed.
 
 And for an iterator like
 
 def things():
 yield 1
 yield 11
 yield 4
 yield 9
 
 I don't know what it could even mean.

http://docs.python.org/reference/simple_stmts.html#the-yield-statement

You could have tried to debug.

Please trim your quotes to the relevant minimum.

-- 
PointedEars

Bitte keine Kopien per E-Mail. / Please do not Cc: me.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread MRAB

On 23/06/2011 00:10, Neal Becker wrote:

Steven D'Aprano wrote:


On Wed, 22 Jun 2011 15:28:23 -0400, Neal Becker wrote:


AFAICT, the python iterator concept only supports readable iterators,
not write. Is this true?

for example:

for e in sequence:
   do something that reads e
   e = blah # will do nothing

I believe this is not a limitation on the for loop, but a limitation on
the python iterator concept.  Is this correct?


Have you tried it? e = blah certainly does not do nothing, regardless
of whether you are in a for loop or not. It binds the name e to the value
blah.



Yes, I understand that e = blah just rebinds e.  I did not mean this as an
example of working code.  I meant to say, does Python have any idiom that allows
iteration over a sequence such that the elements can be assigned?


[snip]
Python has references to objects, but not references to references.
--
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread Steven D'Aprano
On Thu, 23 Jun 2011 09:10 am Neal Becker wrote:

 Steven D'Aprano wrote:
 
 On Wed, 22 Jun 2011 15:28:23 -0400, Neal Becker wrote:
 
 AFAICT, the python iterator concept only supports readable iterators,
 not write. Is this true?
 
 for example:
 
 for e in sequence:
   do something that reads e
   e = blah # will do nothing
 
 I believe this is not a limitation on the for loop, but a limitation on
 the python iterator concept.  Is this correct?
 
 Have you tried it? e = blah certainly does not do nothing, regardless
 of whether you are in a for loop or not. It binds the name e to the value
 blah.
 
 
 Yes, I understand that e = blah just rebinds e.  I did not mean this as an
 example of working code.  I meant to say, does Python have any idiom that
 allows iteration over a sequence such that the elements can be assigned?

Yes. I already gave one:

for i, e in enumerate(seq):
seq[i] = e + 42


If you look at code written before the enumerate built-in, you will often
find code like this:

for i in range(len(seq)):
e = seq[i]
seq[i] = e + 42


Sometimes you'll find code that does this:

i = 0
while i  len(seq):
e = seq[i]
seq[i] = e + 42
i += 1

but don't do that, it's slow.

Or you can do this:

seq[:] = [e+42 for e in seq]

There are others.

[...]
 AFAIK, the above is the only python idiom that allows iteration over a
 sequence
 such that you can write to the sequence.  And THAT is the problem.  In
 many cases, indexing is much less efficient than iteration.

Are you aware that iteration is frequently based on indexing?

In the cases that it isn't, that's because the iterator generates values
lazily, without ever storing them. You *can't* write to them because
there's nowhere to write to! If you want to store the values so they are
writable, then you have to use indexing.

What makes you think that this is a problem in practice? Can you give an
example of some task you can't solve because you (allegedly) can't write to
a sequence?


-- 
Steven

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread Steven D'Aprano
On Thu, 23 Jun 2011 09:30 am Thomas 'PointedEars' Lahn wrote:

 Mel wrote:
 
 Steven D'Aprano wrote:
 I *guess* that what you mean by writable iterators is that rebinding e
 should change seq in place, i.e. you would expect that seq should now
 equal [42, 42]. Is that what you mean? It's not clear.
 
 Fortunately, that's not how it works, and far from being a limitation,
 it would be *disastrous* if iterables worked that way. I can't imagine
 how many bugs would occur from people reassigning to the loop variable,
 forgetting that it had a side-effect of also reassigning to the
 iterable. Fortunately, Python is not that badly designed.
 
 And for an iterator like
 
 def things():
 yield 1
 yield 11
 yield 4
 yield 9
 
 I don't know what it could even mean.
 
 http://docs.python.org/reference/simple_stmts.html#the-yield-statement
 
 You could have tried to debug.

I think you have missed the point of Mel's comment. He knows what the yield
statement does. He doesn't know what it would mean to write to an
iterator like things().

Neither do I.



-- 
Steven

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread Carl Banks
On Wednesday, June 22, 2011 4:10:39 PM UTC-7, Neal Becker wrote:
 AFAIK, the above is the only python idiom that allows iteration over a 
 sequence 
 such that you can write to the sequence.  And THAT is the problem.  In many 
 cases, indexing is much less efficient than iteration.

Well, if your program is such that you can notice a difference between indexing 
and iteration, you probably have better things to worry about.  But whatever.  
You can get the effect you're asking for like this:


class IteratorByProxy(object):
def __init__(self,iterable):
self.set(iterable)
def __iter__(self):
return self
def next(self):
return self.current_iter.next()
def set(self,iterable):
self.current_iter = iter(iterable)

s = IteratorByProxy(xrange(10))
for i in s:
print i
if i == 6:
s.set(xrange(15,20))


Carl Banks
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: writable iterators?

2011-06-22 Thread FunAt Work
Don't relate it anyhow to foreach of perl I would say, although the behaviour 
may be same in some aspect
-- 
http://mail.python.org/mailman/listinfo/python-list