Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterator for custom class in Python 3

I'm trying to port a custom class from Python 2 to Python 3. I can't find the right syntax to port the iterator for the class. Here is a MVCE of the real class and my attempts to solve this so far:

Working Python 2 code:

class Temp:
    def __init__(self):
        self.d = dict()
    def __iter__(self):
        return self.d.iteritems()

temp = Temp()
for thing in temp:
    print(thing)

In the above code iteritems() breaks in Python 3. According to this highly voted answer, "dict.items now does the thing dict.iteritems did in python 2". So I tried that next:

class Temp:
    def __init__(self):
        self.d = dict()
    def __iter__(self):
        return self.d.items()

The above code yields "TypeError: iter() returned non-iterator of type 'dict_items'"

According to this answer, Python 3 requires iterable objects to provide a next() method in addition to the iter method. Well, a dictionary is also iterable, so in my use case I should be able to just pass dictionary's next and iter methods, right?

class Temp:
    def __init__(self):
        self.d = dict()
    def __iter__(self):
        return self.d.__iter__
    def next(self):
        return self.d.next

This time it's giving me "TypeError: iter() returned non-iterator of type 'method-wrapper'".

What am I missing here?

like image 497
Atte Juvonen Avatar asked Feb 06 '18 11:02

Atte Juvonen


People also ask

How do I make an iterator 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 use an iterator in Python 3?

Iterator in python is an object that is used to iterate over iterable objects like lists, tuples, dicts, and sets. The iterator object is initialized using the iter() method. It uses the next() method for iteration. next ( __next__ in Python 3) The next method returns the next value for the iterable.

How do I make a custom iterable class?

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.

What is __ ITER __ in Python?

The __iter__() function returns an iterator for the given object (array, set, tuple, etc. or custom objects). It creates an object that can be accessed one element at a time using __next__() function, which generally comes in handy when dealing with loops. Syntax : iter(object) iter(callable, sentinel)


1 Answers

As the error message suggests, your __iter__ function does not return an iterator, which you can easily fix using the built-in iter function

class Temp:
    def __init__(self):
        self.d = {}
    def __iter__(self):
        return iter(self.d.items())

This will make your class iterable. Alternatively, you may write a generator yourself, like so:

def __iter__(self):
    for key,item in self.d.items():
        yield key,item

If you want to be able to iterate over keys and items separately, i.e. in the form that the usual python3 dictionary can, you can provide additional functions, for example

class Temp:
    def __init__(self, dic):
        self.d = dic

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

    def keys(self):
        return self.d.keys()

    def items(self):
        return self.d.items()

    def values(self):
        return self.d.values()

I'm guessing from the way you phrased it that you don't actually want the next() method to be implemented if not needed. If you would, you would have to somehow turn your whole class into an iterator and somehow keep track of where you are momentarily in this iterator, because dictionaries themselves are not iterators. See also this answer.

like image 64
Banana Avatar answered Sep 28 '22 08:09

Banana