7

I'm a little confused over the difference between iterators and iterables. I've done a lot of reading and have got this much:

Iterator: An object that has __next__ in it’s class. You can call next() on it. All iterators are iterable.

Iterable: An object that defines __iter__ or __getitem__ in it's class. Something is iterable if it can build an iterator using iter(). Not all iterables are iterators.

Is some_dict.items() an iterator? I know that some_dict.iteritems() would be in Python2 right?

I'm just checking because a course I'm doing says it is and I'm pretty sure it's just an iterable (not an iterator).

Thanks for your help :)

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
Ed the Coder
  • 123
  • 2
  • 9
  • Possible duplicate of [What is the difference between dict.items() and dict.iteritems()?](https://stackoverflow.com/questions/10458437/what-is-the-difference-between-dict-items-and-dict-iteritems) – ytu Sep 02 '18 at 09:02
  • @ytu not really a duplicate IMO, and anyway, the accepted answer *incorrectly* addresses the specifics of this one. – juanpa.arrivillaga Sep 02 '18 at 09:03
  • @juanpa.arrivillaga I am aware of that the accepted answer is incorrect. Still discussions there covered pretty much and are enough to solve this question here. – ytu Sep 02 '18 at 09:05
  • I have a feeling that you did not ask what you wanted to ask. `items()` really does not return an iterator, but it does return something which behaves like an iterator, so you should not care. In other words, it does not create a list of all items as it did in python 2, but only generates one by one as you iterate through them. – zvone Sep 02 '18 at 09:07
  • 1
    @zvone But you can't call `next()` on `items`, so surely it doesn't behave like an iterator? In regards to the duplication, I read that answer before and didn't feel it probably wasn't simple enough for me to understand :P Looking back now combined with the answers here I do get it, so am happy to accept duplication if that's the going consensus? (pretty new to stackoverflow) – Ed the Coder Sep 02 '18 at 09:14
  • 1
    @E.Hazledine - true, but I am guessing that OP wanted to know whether it behaved like `items` from python 2 or like `iteritems`, in which case, all of the answers which are correct would lead to the wrong conclusion. Hence my simplified comment – zvone Sep 02 '18 at 09:17

4 Answers4

6

No, it isn't. It is an iterable view of the items in the dict:

>>> next({}.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'dict_items' object is not an iterator
>>>

It's __iter__ method returns a specialized iterator instance:

>>> iter({}.items())
<dict_itemiterator object at 0x10478c1d8>
>>>
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
3

You can test this directly:

from collections import Iterator, Iterable

a = {}
print(isinstance(a, Iterator))  # -> False
print(isinstance(a, Iterable))  # -> True
print(isinstance(a.items(), Iterator))  # -> False
print(isinstance(a.items(), Iterable))  # -> True
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
3

dict.items returns a dict view, according to the docs:

In [5]: d = {1: 2}

In [6]: next(d.items())
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-945b6258a834> in <module>()
----> 1 next(d.items())

TypeError: 'dict_items' object is not an iterator

In [7]: next(iter(d.items()))
Out[7]: (1, 2)

Answering your question, dict.items is not an iterator. It is an iterable object which supports len, __contains__ and reflects changes made in the original dict:

In [14]: d = {1: 2, 3: 4}

In [15]: it = iter(d.items())

In [16]: next(it)
Out[16]: (1, 2)

In [17]: d[3] = 5

In [18]: next(it)
Out[18]: (3, 5)
awesoon
  • 32,469
  • 11
  • 74
  • 99
2

Check it yourselves:

d = {'a': 1, 'b': 2}

it = d.items()
print(next(it))

This results in TypeError: 'dict_items' object is not an iterator.

On the other hand, you can always iterate through d.items() as:

d = {'a': 1, 'b': 2}

for k, v in d.items():
    print(k, v)

Or:

d = {'a': 1, 'b': 2}

it = iter(d.items())
print(next(it))  # ('a', 1)
print(next(it))  # ('b', 2)
Austin
  • 25,759
  • 4
  • 25
  • 48