473,387 Members | 1,791 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

More baby squeaking - iterators in a class

Hello Mr Everyone,

From:
http://docs.python.org/tut/node11.ht...00000000000000

"Define a __iter__() method which returns an object with a next()
method. If the class defines next(), then __iter__() can just return
self:"

The thing is, I tried to define __iter__() directly without explicit
defining next (after all, the conclusion from this passage should
be that it's possible).
class R:
def __init__(self, d):
self.d=d
self.i=len(d)
def __iter__(self):
if self.i == 0:
raise StopIteration
self.i -= 1
return self.d[self.i]

s=R('spam') dir(s) ['__doc__', '__init__', '__iter__', '__module__', 'd', 'i']

Apparently no, there is no next() method. Let's see
if iterator works:
s.__iter__() 'm' s.__iter__() 'a' s.__iter__() 'p' s.__iter__() 's' s.__iter__() Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "<interactive input>", line 7, in __iter__
StopIteration

OK, this part works. But this:
s=R('spam')
for i in s:

print i

Traceback (most recent call last):
File "<interactive input>", line 1, in ?
TypeError: __iter__ returned non-iterator of type 'str'

So which is it? Does next() method HAS to be defined
explicitly? That's what Wikipedia says:

http://en.wikipedia.org/wiki/Iterator#Python

"Any user defined class can support standard iteration (either
implicit or explicit) by defining an __iter__() method which creates
an iterator object. The iterator object then needs to define both an
__iter__() method as well as a next() method."


--
It's a man's life in a Python Programming Association.
Jul 18 '05 #1
13 1402
"Bulba!" <bu***@bulba.com> wrote in message
news:nj********************************@4ax.com...
Hello Mr Everyone,

From:
http://docs.python.org/tut/node11.ht...00000000000000

"Define a __iter__() method which returns an object with a next()
method. If the class defines next(), then __iter__() can just return
self:"

The thing is, I tried to define __iter__() directly without explicit
defining next (after all, the conclusion from this passage should
be that it's possible).
I don't get that from the passage quoted, at all, although it is somewhat
opaque. It says that your __iter__() method must *return an object* with a
next() method; your __iter__() method below doesn't return such an object,
but instead returns a string. It then says that *if* your class defines
next(), which yours doesn't, __iter__() can return self.

[spaces inserted; you should note that many newsreaders strip the TAB
character...]
class R:
def __init__(self, d):
self.d=d
self.i=len(d)
def __iter__(self):
if self.i == 0:
raise StopIteration
self.i -= 1
return self.d[self.i]


Solution: replace "__iter__" with "next" in the class definition above,
then add to the end:

def __iter__(self):
return self
--
I don't actually read my hotmail account, but you can replace hotmail with
excite if you really want to reach me.
Jul 18 '05 #2
Bulba! <bu***@bulba.com> wrote:
So which is it? Does next() method HAS to be defined
explicitly?


It has to be defined, whether explicitly or not (e.g. via a generator).
Alex
Jul 18 '05 #3

"Bulba!" <bu***@bulba.com> wrote in message
news:nj********************************@4ax.com...
"Define a __iter__() method which returns an object with a next()
method. If the class defines next(), then __iter__() can just return
self:"

The thing is, I tried to define __iter__() directly without explicit
defining next (after all, the conclusion from this passage should
be that it's possible).
It is, see below.
class R:
def __init__(self, d):
self.d=d
self.i=len(d)
def __iter__(self):
if self.i == 0:
raise StopIteration
self.i -= 1
return self.d[self.i]


Change 'return' to 'yield'. Then r.__iter__() *will* return a
(generator)iterator with a .next method, as required. But it will only
yield one value before running off the end. Since __iter__ is meant to be
called only once, you need to loop explicitly in the generator. For
instance

def __iter__(self):
i,d = self.i, self.d
while i
i =- 1
yield d[i]

Copying i makes the generator non-destuctive.

(PS, use spaces, not tabs, in posted code.)

Terry J. Reedy

Jul 18 '05 #4
Bulba! wrote:
Hello Mr Everyone,

From:
http://docs.python.org/tut/node11.ht...00000000000000

"Define a __iter__() method which returns an object with a next()
method. If the class defines next(), then __iter__() can just return
self:"

The thing is, I tried to define __iter__() directly without explicit
defining next (after all, the conclusion from this passage should
be that it's possible).
class R:
def __init__(self, d):
self.d=d
self.i=len(d)
def __iter__(self):
if self.i == 0:
raise StopIteration
self.i -= 1
return self.d[self.i]


Here's one way: # (Make __iter__ an iterator)

Py> class R1(object):
def __init__(self, data):
self.data = data
self.i = len(data)
def __iter__(self):
while self.i > 0:
self.i -= 1
yield self.data[self.i]

Py> s=R1('spam')
Py> list(s)
['m', 'a', 'p', 's']
Py> list(s)
[]
Py> s.i = 3
Py> list(s)
['a', 'p', 's']

Here's another way: # (Return something with __iter__ and next methods)

Py> class R2(object):
def __init__(self, data):
self.d = data
self.i = len(data)
def __iter__(self):
return iter(self.d)
Py> s = R2('spam')
Py> list(s)
['s', 'p', 'a', 'm']
Py> list(s)
['s', 'p', 'a', 'm']

--Scott David Daniels
Sc***********@Acm.Org
Jul 18 '05 #5
On Thu, 30 Dec 2004 12:06:31 -0800, Scott David Daniels
<Sc***********@Acm.Org> wrote:
Here's one way: # (Make __iter__ an iterator)
Py> class R1(object):
def __init__(self, data):
self.data = data
self.i = len(data)
def __iter__(self):
while self.i > 0:
self.i -= 1
yield self.data[self.i]


Thanks to everyone for their responses, but it still doesn't work re
returning next() method:
class R3:
def __init__(self, d):
self.d=d
self.i=len(d)
def __iter__(self):
d,i = self.d, self.i
while i>0:
i-=1
yield d[i]
p=R3('eggs')
p.next() Traceback (most recent call last):
File "<interactive input>", line 1, in ?
AttributeError: R3 instance has no attribute 'next' dir(p) ['__doc__', '__init__', '__iter__', '__module__', 'd', 'i'] list(p) ['s', 'g', 'g', 'e']
I tried all the methods advised by you and other posters and they do
return an object with __iter__, but not with the next method.

What's strange is that when it comes to function, it does return
the .next method:

def rev(d):
for i in range (len(d)-1, -1, -1):
yield d[i]
o=rev('eggs')
o <generator object at 0x0120DF58> dir(o) ['__class__', '__delattr__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__iter__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__str__', 'gi_frame',
'gi_running', 'next'] o.next() 's' o.next() 'g' o.next() 'g' o.next() 'e'
The function returns 'generator object', as shown above,
while p is a class instance:
p

<__main__.R3 instance at 0x0123CA58>


--
It's a man's life in a Python Programming Association.
Jul 18 '05 #6
Reread Russel Blau post he is spot on with his comments:
Russel Blau wrote:
I don't get that from the passage quoted, at all, although it is somewhatopaque. It says that your __iter__() method must *return an object* with anext() method; your __iter__() method below doesn't return such an object,but instead returns a string. It then says that *if* your class definesnext(), which yours doesn't, __iter__() can return self.

[spaces inserted; you should note that many newsreaders strip the TAB
character...]
class R:
def __init__(self, d):
self.d=d
self.i=len(d)
def __iter__(self):
if self.i == 0:
raise StopIteration
self.i -= 1
return self.d[self.i]
Solution: replace "__iter__" with "next" in the class definition above,then add to the end:

def __iter__(self):
return self

That works exactly as advertised.

py> s = R('54645656')
.... s.next()
'6'
.... s.next()
'5'
.... s.next()
'6'
.... s.next()
'5'
.... s.next()
'4'
... s.next()
'6'
.... s.next()
'4'
.... s.next()
'5'
.... s.next()
Traceback (most recent call last):
File "<input>", line 1, in ?
File "<input>", line 7, in next
StopIteration

And the other posters showed you how to create an iterator without a
next() .
Other than having no next() method they still work the same.

Jul 18 '05 #7

"Bulba!" <bu***@bulba.com> wrote in message
news:bv********************************@4ax.com...
Thanks to everyone for their responses, but it still doesn't work re
returning next() method:
class R3:
def __init__(self, d):
self.d=d
self.i=len(d)
def __iter__(self):
d,i = self.d, self.i
while i>0:
i-=1
yield d[i]
p=R3('eggs')
p.next()


This is the wrong test for what I and some others thought you were asking.
The requirement for p to be an *iterable* and useable in code such as 'for
i in p' is that iter(p), not p itself, have a .next method, and iter(p)
will. Try ip=iter(p) followed by ip.next and ip.next() instead.

If, for whatever reason, you instead want p to actually be an *iterator*
with a .next (or .getitem) method, then, of course, you have to actually
give it a .next (or .getitem) method.

Terry J. Reedy

Jul 18 '05 #8
Bulba! wrote:

Thanks to everyone for their responses, but it still doesn't work re
returning next() method:

class R3:
def __init__(self, d):
self.d=d
self.i=len(d)
def __iter__(self):
d,i = self.d, self.i
while i>0:
i-=1
yield d[i]

p=R3('eggs')
p.next() [snip]
What's strange is that when it comes to function, it does return
the .next method:

def rev(d):
for i in range (len(d)-1, -1, -1):
yield d[i]

o=rev('eggs') [snip]o.next()

's'


Note the difference here. When you're using the function, you call the
iter function (called rev in your example). When you're using the
class, you haven't called the iter function, only instantiated the class
(i.e. called the __init__ function). Try one of the following:

py> p = R3('eggs')
py> i = p.__iter__()
py> i.next()
's'

or

py> p = R3('eggs')
py> i = iter(p)
py> i.next()
's'

Steve
Jul 18 '05 #9
Terry Reedy wrote:
This is the wrong test for what I and some others thought you were asking.The requirement for p to be an *iterable* and useable in code such as 'fori in p' is that iter(p), not p itself, have a .next method, and iter(p)will. Try ip=iter(p) followed by ip.next and ip.next() instead. Does that mean if you dont't call iter(() on your instance or have a
next() method you can't do this: class R3:
def __init__(self, d):
self.d=d
self.i=len(d)
def __iter__(self):
d,i = self.d, self.i
while i>0:
i-=1
yield d[i]

p=R3('eggs')
for i in p:
print i


I am asking because I want to fully understand what makes an
*iterator*.

M.E.Farmer

Jul 18 '05 #10
On Fri, 31 Dec 2004 16:31:45 GMT, Steven Bethard
<st************@gmail.com> wrote:
py> p = R3('eggs')
py> i = p.__iter__()
py> i.next()
's' or py> p = R3('eggs')
py> i = iter(p)
py> i.next()
's'


And that is precisely what I needed to know. Thanks, to you,
Terry and everyone who took time to look at it.

--
It's a man's life in a Python Programming Association.
Jul 18 '05 #11

"M.E.Farmer" <me*****@hotmail.com> wrote in message
news:11**********************@c13g2000cwb.googlegr oups.com...
Terry Reedy wrote:
will. Try ip=iter(p) followed by ip.next and ip.next() instead.
Does that mean if you dont't call iter(() on your instance or have a
next() method you can't do this:
> p=R3('eggs')
> for i in p:
> print i


Ignoring the older iteration method based on __getitem__, which I recommend
you do ignore, yes, you cannot do that.
I am asking because I want to fully understand what makes an
*iterator*.


An iterator is an object with an __iter__ method that returns 'self' and a
parameterless .next() method that on each call either returns an object or
raises StopIteration.

An iterable is an object with an __iter__ method that returns an iterator.

A generator function (one containing yield in the code body), when called,
returns a generator, which is a particular type of iterator. So, a class
with .__iter__ written as a generator function has iterable instances.

I can think of three reasons to go this latter route:
1. Writing a generator function may be easier that writing a standard
function for .next.
2. The resulting iteration may be faster.
3. Iterating with a separate generator allows iteration without disturbing
the data of the instance (ie, non destructively). This means that one can
iterate more than once, even more than once at the same time. Consider
'multiplying' a sequence by itself:

(i,j) for i in iterable for j in iterable

iter(iterable) is called once and then once again for each item yielded by
the first call.

Terry J. Reedy

Jul 18 '05 #12
Terry ,
Thank you for the explanation . That is much clearer now, I have played
a bit with generators but have never tried to create a custom iterator.
I am just now getting into the internals part of python objects... this
langauage is still amazing to me!
The reason I asked the question was because I tried that code I posted
and it worked fine in python2.2.3 ?
Ignoring the older iteration method based on __getitem__, which I recommendyou do ignore, yes, you cannot do that.


py>class R3:
.... def __init__(self, d):
.... self.d=d
.... self.i=len(d)
.... def __iter__(self):
.... d,i = self.d, self.i
.... while i>0:
.... i-=1
.... yield d[i]
....
py>a = R3('qwerty')
py>dir(a)
['__doc__', '__init__', '__iter__', '__module__', 'd', 'i']
py>for i in a:
.... print i
....
y
t
r
e
w
q
Ok I don't see __getitem__ anywhere in this object.
Still scratchin my head? Why does this work?
M.E.Farmer

Jul 18 '05 #13
py> from __future__ import generators
Hello again,
I was thinking about the __iter__ and what you were saying about
generators, so I opened up pyshell and started typing.
py> class R3:
.... def __init__(self, d):
.... self.d=d
.... self.i=len(d)
.... def __iter__(self):
.... d,i = self.d, self.i
.... while i>0:
.... i-=1
.... yield d[i]
....
py> r = R3('qwerty')
py> r.__class__
<class __main__.R3 at 0x01440A38>
py> r.__iter__
<bound method R3.__iter__ of <__main__.R3 instance at 0x0141BFB0>>
py> r.__iter__()
<stackless.generator object at 0x0143FE38>
py> a = r.__iter__()
py> a.next()
'y'

py> a.next()
't'
py> a.next()
'r'
py> a.next()
'e'
py> a.next()
'w'
py> a.next()
'q'
py> a.next()
Traceback (most recent call last):
File "<input>", line 1, in ?
StopIteration

Doh! ok now I get it __iter__ RETURNS a generator ;)
It seems so obvious now I look at it.
Sometimes I am a bit slow to catch on , but I never forget, much.

M.E.Farmer
Deeper down the rabbit hole.

M.E.Farmer wrote: Terry ,
Thank you for the explanation . That is much clearer now, I have played a bit with generators but have never tried to create a custom iterator. I am just now getting into the internals part of python objects... this langauage is still amazing to me!
The reason I asked the question was because I tried that code I posted and it worked fine in python2.2.3 ?
Ignoring the older iteration method based on __getitem__, which I

recommend
you do ignore, yes, you cannot do that.


py>class R3:
... def __init__(self, d):
... self.d=d
... self.i=len(d)
... def __iter__(self):
... d,i = self.d, self.i
... while i>0:
... i-=1
... yield d[i]
...
py>a = R3('qwerty')
py>dir(a)
['__doc__', '__init__', '__iter__', '__module__', 'd', 'i']
py>for i in a:
... print i
...
y
t
r
e
w
q
Ok I don't see __getitem__ anywhere in this object.
Still scratchin my head? Why does this work?
M.E.Farmer


Jul 18 '05 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Alexander Stippler | last post by:
Hi, I have to design some two dimensional iterators and I'm not quite sure about the design. I'd like to have the iterators mostly STL-like. The STL does not contain two dimensional iterators, I...
4
by: Merlin | last post by:
Hi, I am a C++ developer and would like to implement container classes for various types of objects. I use MS Visual C++ to compile my code. Nevertheless I like to write code that is independent...
4
by: matthurne | last post by:
I am working through exercise 8-2 in Accelerated C++...I am implementing the function equal(b, e, b2) where b is an iterator for the first element in a container, e is an iterator pointing to one...
1
by: Marcin Kaliciński | last post by:
template<class RanAccIt> void some_algorithm(RanAccIt begin, RanAccIt end) { // this algorithm involves calling std::lexicographical_compare // on range [begin, end), and on reverse of this range...
90
by: John Salerno | last post by:
I'm a little confused. Why doesn't s evaluate to True in the first part, but it does in the second? Is the first statement something different? False print 'hi' hi Thanks.
6
by: gexarchakos | last post by:
Hi there, Please give me at least a hint... I have a problem implementing a function object with parameters two iterators. That is: A class 'node' produces messages using a routing policy....
7
by: desktop | last post by:
I am not sure I quite understand the use of iterators. I have this int array: int a = {1,2,3,4,5} I would now like to make an iterator to the first and last element: std::iterator<intiter;...
18
by: desktop | last post by:
1) I have this code: std::list<intmylist; mylist.push_back(1); mylist.push_back(2); mylist.push_back(3); mylist.push_back(4);
3
by: Jess | last post by:
Hello, Iterators are typically put into five different categories, namely input iterator, output iterator, forward iterator, bidirectional iterator and random iterator. The differences come...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.