[Tutor] making object iterable

Alex Hall mehgcap at gmail.com
Sat Feb 5 21:50:22 CET 2011


On 2/5/11, Peter Otten <__peter__ at web.de> wrote:
> Alex Hall wrote:
>
>> Hi all,
>> I have a class which has a list as an attribute, meaning you must say
>> something like:
>> for result in obj.results: ...
>> I want to make life a bit easier and let users just say:
>> for result in obj: ...
>> Here is what I have tried to make my class into an iterable one, yet I
>> get an error saying that the class does not support indexing:
>
> Please remember to always cut-and-paste code and traceback.
>
>>  def __iter__(self):
>>   #makes this class indexable instead of having to use its "results" list
>>   return self.iterate()
>>
>>  def iterate(self):
>>   i=0
>>   while i<len(self.results):
>>    yield self.results[i]
>>    i+=1
>>
>> I am not sure why this does not work, unless I am misunderstanding
>> something about iterators and iterables? I thought an iterable, which
>> is what I am shooting for, was an iterator on steroids, allowing
>> indexing, multiple passes over the list, and all that. Do I want to
>> make this an iterator instead of an iterable?
>
> It *does* work:
>
>>>> class A(object):
> ...     def __init__(self, results):
> ...             self.results = results
> ...     def __iter__(self):
> ...             return self.iterate()
> ...     def iterate(self):
> ...             i = 0
> ...             while i < len(self.results):
> ...                     yield self.results[i]
> ...                     i += 1
> ...
>>>> a = A("abc")
>>>> for item in a:
> ...     print item
> ...
> a
> b
> c
Yes, I get the same thing. However, when you try to index, as in a[0],
you have problems. Here are two lines from my program:
for i in res: print i
This works as expected, printing every object in res.results, just as I wanted.

for i in range(len(res)): print str(i+1)+": "+str(res[i])
This gives me an error, on this line, that "TypeError: 'SearchResults'
object does not support indexing". So it seems that I can iterate over
the list, but not get at a given element. What builtin method do I
need to overload to do this?


>
> Perhaps self.results is not what you think it is. Check by adding the
> apprpriate print statement.
>
> By the way, there are simpler alternatives to delegate iteration to an
> attribute:
>
>>>> class B(object):
> ...     def __init__(self, results):
> ...             self.results = results
> ...     def __iter__(self):
> ...             return iter(self.results)
> ...
>>>> b = B("abc")
>>>> for item in b:
> ...     print item
> ...
> a
> b
> c
True, and I have made this change.
>
>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> http://mail.python.org/mailman/listinfo/tutor
>


-- 
Have a great day,
Alex (msg sent from GMail website)
mehgcap at gmail.com; http://www.facebook.com/mehgcap


More information about the Tutor mailing list