Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Method returning an Iterable Object

4 views
Skip to first unread message

Anjanesh Lekshminarayanan

unread,
Jan 26, 2009, 11:31:21 AM1/26/09
to Python List
Is there a way to return an iterable object ?

class twoTimes:
def __init__(self, n):
self.__n = n

def getNext():
self.__n *= 2
return self.__n


t = twoTimes(5)
while (n in t.getNext()): # while (n in t):
print (n)

--
Anjanesh Lekshmnarayanan

Steve Holden

unread,
Jan 26, 2009, 11:44:01 AM1/26/09
to pytho...@python.org
Anjanesh Lekshminarayanan wrote:
> Is there a way to return an iterable object ?
>
> class twoTimes:
> def __init__(self, n):
> self.__n = n
>
> def getNext():
> self.__n *= 2
> return self.__n
>
>
> t = twoTimes(5)
> while (n in t.getNext()): # while (n in t):
> print (n)
>
Sure:

class EveryOther:
def __init__(self, seq):
self.seq = seq self.idx = 0
def next(self):
self.idx += 1
if self.idx >= len(self.seq):
raise StopIteration
value = self.seq[self.idx]
self.idx += 1
return value
def __iter__(self):
return self


print [x for x in EveryOther(range(10))
[1, 3, 5, 7, 9]

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

Andreas Waldenburger

unread,
Jan 26, 2009, 12:01:52 PM1/26/09
to
On Mon, 26 Jan 2009 22:01:21 +0530 Anjanesh Lekshminarayanan
<ma...@anjanesh.net> wrote:

> Is there a way to return an iterable object ?
>
> class twoTimes:
> def __init__(self, n):
> self.__n = n
>
> def getNext():
> self.__n *= 2
> return self.__n
>
>

Rename getNext() to next() and create another method named __iter__()
that just returns self. TwoTimes is now an iterator.

You can also replace the whole class with a function thusly:

def two_times(n):
for k in itertools.count(1):
yield n * (2**k)

This function is then called a generator (because it generates an
iterator). You can now say

infinitely_doubling_numbers = two_times(2)
for number in in infinitely_doubling_numbers:
print number

to the same effect as the iterator version above.

python.org seems uncooperative at the moment, but look up iterators or
the iterator protocol and generators if it works for you.


> t = twoTimes(5)
> while (n in t.getNext()): # while (n in t):
> print (n)
>

You are aware that this is an infinite loop, as is my example above BTW?
(Probably just an example, but I ask just in case.)

Also, could it be that you mean "for n in t"?

regards
/W

--
My real email address is constructed by swapping the domain with the
recipient (local part).

Anjanesh Lekshminarayanan

unread,
Jan 26, 2009, 1:35:53 PM1/26/09
to pytho...@python.org
> You can also replace the whole class with a function thusly:
>
> def two_times(n):
> for k in itertools.count(1):
> yield n * (2**k)
>
> This function is then called a generator (because it generates an
> iterator). You can now say
>
> infinitely_doubling_numbers = two_times(2)
> for number in in infinitely_doubling_numbers:
> print number

Oh..this is new. Will checkup itertools. Thanks.

>> t = twoTimes(5)
>> while (n in t.getNext()): # while (n in t):
>> print (n)
>>
> You are aware that this is an infinite loop, as is my example above BTW?
> (Probably just an example, but I ask just in case.)

I was aware this was an infinite loop - just didnt want to put more
code for an example.

Andreas Waldenburger

unread,
Jan 26, 2009, 2:28:04 PM1/26/09
to
On Tue, 27 Jan 2009 00:05:53 +0530 Anjanesh Lekshminarayanan
<ma...@anjanesh.net> wrote:

> > You can also replace the whole class with a function thusly:
> >
> > def two_times(n):
> > for k in itertools.count(1):
> > yield n * (2**k)
> >
> > This function is then called a generator (because it generates an
> > iterator). You can now say
> >
> > infinitely_doubling_numbers = two_times(2)
> > for number in in infinitely_doubling_numbers:
> > print number
>
> Oh..this is new. Will checkup itertools. Thanks.
>

OK, happy I could help. But my point was the yield statement (in case
you didn't know about yield).

Anjanesh Lekshminarayanan

unread,
Jan 26, 2009, 10:16:38 PM1/26/09
to pytho...@python.org
But how come a raise StopIteration in the next() method doesnt need to
be caught ? It works without breaking.

class twoTimes:
max = 10**10

def __init__(self, n):
self.__n = n

def next(self):
if self.__n > self.max:
raise StopIteration


self.__n *= 2
return self.__n

def __iter__(self):
return self


t = twoTimes(5)
c = 0

print (t.next())
print (t.next())

for n in t:
print n


Anjanesh

James Mills

unread,
Jan 26, 2009, 10:33:22 PM1/26/09
to Anjanesh Lekshminarayanan, pytho...@python.org
On Tue, Jan 27, 2009 at 1:16 PM, Anjanesh Lekshminarayanan
<ma...@anjanesh.net> wrote:
> But how come a raise StopIteration in the next() method doesnt need to
> be caught ? It works without breaking.

Because this exception is specially dealt
with when iterating over an iterator. The
"raise StopIteration" is what causes the
iteration to stop.

Consider:

>>> x = EveryOther(xrange(10))
>>> x.next()
0
>>> x.next()
2
>>> x.next()
4
>>> x.next()
6
>>> x.next()
8
>>> x.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "foo.py", line 12, in next
raise StopIteration
StopIteration
>>> x = EveryOther(xrange(10))
>>> list(x)
[0, 2, 4, 6, 8]
>>>

cheers
James

Terry Reedy

unread,
Jan 26, 2009, 10:51:13 PM1/26/09
to pytho...@python.org
Anjanesh Lekshminarayanan wrote:
> But how come a raise StopIteration in the next() method doesnt need to
> be caught ? It works without breaking.

The for-loop looks for and catches StopIteration. It is an essential
part of what defines a finite iterator.
(Note, in 3.0, next is renamed __next__ in conformance with all other
special methods. In 2.6, the rename is optional, I believe.)

> class twoTimes:
> max = 10**10
>

> def __init__(self, n):
> self.__n = n

There is no reason to mangle the attribute name.
Max should be a parameter, and self.max = max added to the init.

>
> def next(self):
> if self.__n > self.max:
> raise StopIteration

> self.__n *= 2
> return self.__n

Are you sure you do not want to return once the initial value of n
passed to init?
>
> def __iter__(self):
> return self

Once you understand the above, you can rewrite it as a generator function:

def two_times(num, stop):
while num < stop:
yield num
num *=2

The two last lines can be switches if desired.

> t = twoTimes(5)
> c = 0
>
> print (t.next())
> print (t.next())
>
> for n in t:
> print n

>>> print(list(two_times(5,687)))
[5, 10, 20, 40, 80, 160, 320, 640]

Terry Jan Reedy

0 new messages