Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iter() returned non-iterator of type 'dict_items'

This is driving me insane. Below is a class I was messing around with, the goal was to have a way to support dynamic attribute assignment. Please forget for a moment the poor implementation or why I didn't just use a dictionary, I know there are other ways to do this (such as Enum) but this was my test code before and now it became my quest to find out why it's not working.

class Family(object):
    def children(self):
        return self.__dict__.values()

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __getitem__(self, item):
        return self.__dict__[item]

    def __repr__(self):
        return str(self.__dict__)

    def __iter__(self):
        return self.__dict__.items()

This all seems fine, and I initiated a test object as follows:

foo = Family()
foo.a = 'foo'
foo.b = 'bar'

[i for i in foo]

Now the expected outcome was [('a', 'foo'), ('b', 'bar')], but what I got was this instead:

TypeError: iter() returned non-iterator of type 'dict_items'

I thought I might have messed up the __iter__ method, so I checked as follow:

type(foo.__iter__())
# <class 'dict_items'>
type(foo.__dict__.items())
# <class 'dict_items'>

[i for i in foo.__dict.__items()]
# [('a', 'foo'), ('b', 'bar')]

foo.__dict__.items() == foo.__iter__()
# True

If they're both identical, why doesn't [i for i in foo] work?

like image 430
r.ook Avatar asked Sep 29 '18 03:09

r.ook


1 Answers

What about this:

def __iter__(self):
    return iter(self.__dict__.items())

Python wants an iterator, not a list (or other list-like/dict-like object)

Remember: a list or dict is not an iterator, an iterator is usually (for easy-understanding) a pointer (cursor) pointing to an item of the list or dict.

like image 80
shawn Avatar answered Oct 15 '22 11:10

shawn