Re: [Tutor] In-place changes on loops

2005-02-03 Thread Danny Yoo



> But let's change it to what I think you were thinking of:
>
> ###
> def lstrip(string, chars):
> scratchspace = list(string)   ## get a mutable list of characters
> for x in scratchspace:
> if x in chars:
> scratchspace[i] = ''
> return ''.join(scratchspace)
> ###
>
> This works fine.


Hi Sandip,

Doh.  I hate people who make blanket assertions like that without even
doing a minimal test.  Even if it is myself.  *grin*



The code above is just broken, since there is no index 'i'.  Let me try to
fix it.

###
def lstrip(string, chars):
scratchspace = list(string)   ## get a mutable list of characters
for (i, x) in enumerate(scratchspace):
if x in chars:
scratchspace[i] = ''
return ''.join(scratchspace)
###



I'm not going to make the same mistake twice: we're going to test this
sucker.  *grin*

###
>>> lstrip("hello world", "he")
'llo world'
>>> lstrip("hello world", "eh")
'llo world'
###



Everything looks peachy... except:

###
>>> lstrip("hello world", "aeiou")
'hll wrld'
###

Ah!  That's not right either!


Ok, one more time:

###
def lstrip(string, chars):
scratchspace = list(string)   ## get a mutable list of characters
for (i, x) in enumerate(scratchspace):
if x in chars:
scratchspace[i] = ''
else:
break
return ''.join(scratchspace)
###


Quick sanity check:

###
>>> lstrip("hello world", "eh")
'llo world'
>>> lstrip("hello world", "he")
'llo world'
>>> lstrip("hello world", "aeiou")
'hello world'
###


Finally.  *grin*


Anyway, I wanted to apologize; I should have tested my code.

___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


[Tutor] In-place changes on loops

2005-02-03 Thread Danny Yoo


On Thu, 3 Feb 2005, Sandip Bhattacharya wrote:

> >for x in string:
> >if x in chars:
> >string[i] = ''
>
> I just have a hangover from other languages, but I really wanted to know
> how Python handles iteration over a variable which is being changed
> within the loop itself. Is the "for" condition evaluated in every loop?

Hi Sandip,

Strings are immutable, so the above code won't work.  *grin*


But let's change it to what I think you were thinking of:

###
def lstrip(string, chars):
scratchspace = list(string)   ## get a mutable list of characters
for x in scratchspace:
if x in chars:
scratchspace[i] = ''
return ''.join(scratchspace)
###

This works fine.  In-place list changes that don't modify list structure
will do ok.


When we do structural changes to a list that we're iterating across, then
we do have to be careful.  The Reference Manual does mention caution near
the bottom of:

http://www.python.org/doc/ref/for.html


When we have an statement of the form:

### Pseudocode ###
for  in :

##

then Python does evaluate  just once.


However, what it gets back is an "iterator", an object that marches across
a sequence.  For example:

###
>>> message = list("this is a test")
>>> iterator = iter(message)
>>> iterator.next()
't'
>>> iterator.next()
'h'
>>> iterator.next()
'i'
>>> iterator.next()
's'
###

In effect, the for loop repeatedly calls next() on an iterator until it
exhausts itself.  The iterator doesn't try to be smart, so if we start
mutating the list that backs the iterator, we do risk skipping elements.


Let's try an experiment:

###
>>> message = list("testing")
>>> iterator = iter(message)
>>> iterator.next()
't'
>>> iterator.next()
'e'
>>> message.insert(0, "x")
>>> iterator.next()
'e'
>>> iterator.next()
's'
###


The 'insert()' shoves all the elements one place right.  But, blissfully
ignorant, the iterator doesn't shift itself, but instead stays in place.
So the next call to next() revisits that 'e' character.


Does this make sense?  Please feel free to ask more questions about this.

___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor