Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python make class iterable by returning embedded iterable

I have a class in python, which has an iterable as instance variable. I want to iterate the instances of the class by iterating over the embedded iterable.

I implemented this as follows:

def __iter__(self):
    return self._iterable.__iter__()

I don't really feel that comfortable calling the __iter__() method on the iterable, as it is a special method. Is this how you would solve this problem in python or is there a more elegant solution?

like image 987
jzwiener Avatar asked Mar 05 '12 20:03

jzwiener


People also ask

How do I make an iterable class in Python?

To create an object/class as an iterator you have to implement the methods __iter__() and __next__() to your object. As you have learned in the Python Classes/Objects chapter, all classes have a function called __init__() , which allows you to do some initializing when the object is being created.

How do I return an iterable in Python?

Iterator objects in python conform to the iterator protocol, which basically means they provide two methods: __iter__() and __next__() . The __iter__ returns the iterator object and is implicitly called at the start of loops. The __next__() method returns the next value and is implicitly called at each loop increment.

How do I make a class object iterable?

To make your class Iterable we need to override __iter__() function inside our class i.e. This function should return the object of Iterator class associated with this Iterable class. Contains List of Junior and senior team members and also overrides the __iter__() function. It overrides the __iter__() function.

Which functions return an iterable with a next () method that yields the next element in a sequence?

The __iter__() method returns the iterator object itself. If required, some initialization can be performed. The __next__() method must return the next item in the sequence. On reaching the end, and in subsequent calls, it must raise StopIteration .


1 Answers

The "best" way to way to delegate __iter__ would be:

def __iter__(self):
    return iter(self._iterable)

Alternately, it might be worth knowing about:

def __iter__(self):
    for item in self._iterable:
        yield item

Which will let you fiddle with each item before returning it (ex, if you wanted yield item * 2).

And as @Lattyware mentions in the comments, PEP380 (slated for inclusion in Python 3.3) will allow:

def __iter__(self):
    yield from self._iterable

Note that it may be tempting to do something like:

def __init__(self, iterable):
    self.__iter__ = iterable.__iter__

But this won't work: iter(foo) calls the __iter__ method on type(foo) directly, bypassing foo.__iter__. Consider, for example:

class SurprisingIter(object):
    def __init__(self):
        self.__iter__ = lambda self: iter("abc")

    def __iter__(self):
        return iter([1, 2, 3])

You would expect that list(SurprisingIter()) would return ["a", "b", "c"], but it actually returns [1, 2, 3].

like image 149
David Wolever Avatar answered Nov 15 '22 23:11

David Wolever