[Python-bugs-list] [ python-Bugs-696777 ] How to make a class iterable using a member generator.

SourceForge.net noreply@sourceforge.net
Thu, 08 May 2003 09:22:12 -0700


Bugs item #696777, was opened at 2003-03-03 14:17
Message generated for change (Settings changed) made by rhettinger
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=696777&group_id=5470

Category: Documentation
Group: Python 2.2.2
Status: Open
Resolution: None
Priority: 5
Submitted By: Bjorn Pettersen (bpettersen)
>Assigned to: Raymond Hettinger (rhettinger)
Summary: How to make a class iterable using a member generator.

Initial Comment:
This should probably go at the end of 2.2.5 (LibRef). [I 
was trying all possible variations of __iter__ returning 
self, with next() as a method...]

"""If you are designing a class that should be iterable, 
i.e. you want to be able to say "for x in myClass:...", 
and, you also want the convenience of using a member 
function that is a generator to provide the items, your 
class' __iter__() method should return "self.myGenerator
(self)". The object returned from this call is an iterator-
generator that implements both of the required __iter__() 
and next() methods.

Example:
   class Range10:
       def __init__(self): self.scale = 5
       def __iter__(self):
           return Range10.generateItems(self)
       def generateItems(self):
           for i in range(10): yield i * self.scale

There are a couple of subtleties here. First, only "user-
defined functions" are converted to methods when 
accessed through a class or instance, i.e.myObject.foo
() will extract the foo function wrap it up as a method 
object, insert myObject in the argument list and call it 
(LibRef: 3.2/Callable types/User-defined methods). 
[thanks to Alex M. for clarifying this issue for me]

This automatic conversion does not happen for any 
other type of objects defined inside class scope. In our 
case, generateItems() will be a generator-iterator, i.e. 
not a "user-defined function". Thus the conversion to an 
instance method does not happen, and it is left as a 
static method of the class. [this seems like it might be 
a bug to me...].

To get around this irregularity, make sure your __iter__() 
calls generateItems() as a static method, and explictly 
passes self.
"""

-- bjorn


----------------------------------------------------------------------

Comment By: Terry J. Reedy (tjreedy)
Date: 2003-03-09 12:57

Message:
Logged In: YES 
user_id=593130

As others have posted (with examples) on both c.l.py and 
py-dev, it is both possible and simpler to write __init__ 
itself as a generator function, thereby returning a 
generator-iterator object with the requisite __init_() and 
next() methods.. Since this does not seem to be obvious to 
many people, I would agree that *this* should be 
mentioned in the docs.  All the rest of the discussion about 
access and static methods is irrelevant for this purpose.

>>> from __future__ import generators
>>> class Range10:
...   def __init__(self,scale):
...     self.scale = scale
...   def __iter__(self):
...     scale = self.scale
...     for i in range(10): yield i * scale
...
>>> for i in Range10(4):
...   print i
...
0
4
8
12
16
20
24
28
32
36


----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=696777&group_id=5470