Strange behaviour with reversed()
Terry Reedy
tjreedy at udel.edu
Thu Oct 18 15:11:58 EDT 2007
"Steven D'Aprano" <steve at REMOVE-THIS-cybersource.com.au> wrote in message
news:13hdochic30oo43 at corp.supernews.com...
|I don't understand how reversed() is operating. I've read the description
| in the docs:
|
| reversed(seq)
| Return a reverse iterator. seq must be an object which supports the
| sequence protocol (the __len__() method and the __getitem__() method with
| integer arguments starting at 0). New in version 2.4.
The input specification strongly suggests that rev.next() successively
yields seq[len(seq)-1], ..., seq[0]
The main question is when len(seq) is called -- on creation as it is, or
immediately before the first yield as you appear to expect, and as it would
be in this generator (which does NOT match the actual implementation):
def rev(seq):
n = len(seq)
while n:
n =-1
yield seq[n]
If len(seq) were called repeatedly (after the yield, for instance), then
termination would no longer guaranteed (see below).
I suppose the doc could be augmented with "The iterator is intialized once
with len(sequence) when it is created, rather than when first used or
anytime thereafter." But I wonder whether that would confuse those not
thinking about corner case nuances.
| and help(reversed) but neither gives any insight to what happens when you
| use reversed() on a sequence, then modify the sequence.
The sequence can potentially be modified between all calls to RL.next, and
not just before the first as in your examples.
abcs = list('abc')
for a in reversed(abcs):
print a
abcs.append(a)
The 'reverse' of a changing sequence, especially one changing in length, is
a poorly defined concept.
| >>> L = list("abc")
| >>> RL = reversed(L)
| >>> del L
| >>> list(RL)
| ['c', 'b', 'a']
|
| This suggests that reversed() makes a copy of the list:
Nope. 'del L' merely removes the association between 'L' and the list,
leaving the internal association between RL and the list and hence the list
itself. So the above is consistent with storing a reference (and an index
initialized to len-1).
| >>> L = list("abc")
| >>> RL = reversed(L)
| >>> L.append("d")
| >>> list(RL)
| ['c', 'b', 'a']
|
| This suggests that reversed() uses a reference to the original list:
It suggests that it uses a reference and an index initialized to len-1 when
reversed is called (rather than when RL.next is first called).
| >>> RL = reversed(L)
| >>> L[0] = 'e'
| >>> list(RL)
| ['d', 'c', 'b', 'e']
|
| And these examples suggests that reversed() is confused, or at least
| confusing:
This is completely consist with iterating down via reference and index.
| >>> RL = reversed(L)
| >>> del L[2]
| >>> list(RL)
| []
In the internal loop of list, RL first tries to return L[2]. But that
raises an exception, so RL quits
Terry Jan Reedy
More information about the Python-list
mailing list