Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Python: Dev

Confusing listreverseiterator Behavior

 

 

Python dev RSS feed   Index | Next | Previous | View Threaded


armin.ronacher at active-4

Aug 26, 2008, 12:05 PM

Post #1 of 6 (770 views)
Permalink
Confusing listreverseiterator Behavior

Hi,

I stumbled upon a confusing listreverseiterator behavior:

>>> l = [1, 2, 3, 4]
>>> i = iter(l)
>>> ri = reversed(l)
>>> len(i)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'listiterator' has no len()
>>> len(ri)
4
>>> ri.next()
4
>>> len(ri)
3

This is the only reverse iterator with that sort of behavior. Is
that intentional if yes, why? I stumbled upon that when writing a
templating engine that tried to lazily get the length of the sequence /
iterator but failed doing so after the first iteration because the
length of the reverse iterator changes every iteration.

Regards,
Armin

_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


hall.jeff at gmail

Aug 26, 2008, 12:21 PM

Post #2 of 6 (731 views)
Permalink
Re: Confusing listreverseiterator Behavior [In reply to]

Unless I'm misconstruing something the problem is that reversed returns two
different object types depending on if it's a list or a tuple

>>> l = [1,2,3,4]
>>> i = iter(l)
>>> ri = reversed(l)
>>> l
[1, 2, 3, 4]
>>> ri
<listreverseiterator object at 0x00D5C8F0>
>>> i
<listiterator object at 0x00D5C3F0>
>>> t = (1,2,3,4)
>>> it = iter(t)
>>> rit = reversed(t)
>>> it
<tupleiterator object at 0x00D5C030>
>>> rit
<reversed object at 0x00D5CC90>
>>>

reversing a tuple (or a string) returns a "reversed object"
reversing a list returns a "listreverseiterator"

definitely an inconsistency


hall.jeff at gmail

Aug 26, 2008, 12:47 PM

Post #3 of 6 (719 views)
Permalink
Re: Confusing listreverseiterator Behavior [In reply to]

I realized after I fired off my response that this was still bugging me...
it appears that the documentation is incorrect

from 2.1 Built-in Functions (v2.5 in case it matters... a quick search of
bugs doesn't seem to show anything though)
*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 above appears to only be true for lists. For
tuples and strings it creates a reverse OBJECT which behaves slightly
differently (notably by not including a len() method as you noticed)

I can't find how to actually create a "tuplereverseiterator" or
"stringreverseiterator" objects... nor does there appear to be a way to
create a "reversed" object from a list...

Just tested this
s = 'bob'
t = (1,2,3,4)
l = [1,2,3,4)
rs = reversed(s)
rt = reversed(t)
rl = reversed(l)

type(rs)
<type 'reversed'>
type(rt)
<type 'reversed'>
type(rl)
<type 'listreverseiterator'>
type(rs) == type(rt)
True
type(rs) == type(rl)
False

Surely this isn't intentional?

--------
Haikus are easy
Most make very little sense
Refrigerator


armin.ronacher at active-4

Aug 26, 2008, 1:04 PM

Post #4 of 6 (721 views)
Permalink
Re: Confusing listreverseiterator Behavior [In reply to]

Jeff Hall <hall.jeff <at> gmail.com> writes:

> 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 above appears to only be true for lists. For
> tuples and strings it creates a reverse OBJECT which behaves slightly
> differently (notably by not including a len() method as you noticed)
> I can't find how to actually create a "tuplereverseiterator" or
> "stringreverseiterator" objects... nor does there appear to be a way to
> create a "reversed" object from a list...
That's an implementation detail what exactly the reverse iterator is. The
same applies to iter() calls. iter("foo") for example returns a iterator
type, iter([]) returns a list iterator. The thing you quoted above is the
requirement for the object that you pass to reverse(), not the object
returned which is some kind of iterator that happens to iterate over the
sequence in reverse.

The problem I personally have with it is that the listreverseiterator is the
only iterator in the standard library that changes the length during
iteration and that it's the only reverse iterator that has a length. Even
more stunning as the normal iterator doesn't have one.


Regards,
Armin


_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


python at rcn

Aug 26, 2008, 1:05 PM

Post #5 of 6 (725 views)
Permalink
Re: Confusing listreverseiterator Behavior [In reply to]

From: "Armin Ronacher" <armin.ronacher [at] active-4>
>>>> len(ri)
> 4
>>>> ri.next()
> 4
>>>> len(ri)
> 3
>
> This is the only reverse iterator with that sort of behavior.

Use the bug tracker please and assign to me.
At one time, some iterators had the ability to know
their own length and that would change as the
iterator got consumed. Later, it was decided
that iterators should not report length and should
instead report a length hint. It looks like listreversediterator
got missed when this was changed.


Raymond
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


g.brandl at gmx

Aug 26, 2008, 1:30 PM

Post #6 of 6 (724 views)
Permalink
Re: Confusing listreverseiterator Behavior [In reply to]

Jeff Hall schrieb:
> I realized after I fired off my response that this was still bugging
> me... it appears that the documentation is incorrect
>
> from 2.1 Built-in Functions (v2.5 in case it matters... a quick search
> of bugs doesn't seem to show anything though)
>
> *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 above appears to only be true for lists.

Not at all. (I think you misread; the __len__ method must be present on
the argument, not the returned object.)

> For tuples and strings it
> creates a reverse OBJECT which behaves slightly differently (notably by
> not including a len() method as you noticed)
>
> I can't find how to actually create a "tuplereverseiterator" or
> "stringreverseiterator" objects... nor does there appear to be a way to
> create a "reversed" object from a list...

You don't need to. An object returned by reversed() only needs to follow
the iterator protocol. Whether it is a listreverseiterator or a general
reversed object doesn't matter.

In fact, reversed() calls __reversed__ on its argument if it exists, so that
custom types may provide their own optimized reverse iterator.

Georg

_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com

Python dev RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.