Reputation:
I found that:
>>> a={'x':42, 'y':3.14, 'z':7}
>>> b=a.__iter__()
>>> b.__dir__()
['__next__', ..., '__iter__', ...]
>>> b
<set_iterator object at 0x7efdd4e5afc0>
Does an iterator always have the __iter__
method?
According to https://stackoverflow.com/a/9884259 an iterator also an iterable. If it is true that an iterator always has __iter__
method?
Upvotes: 22
Views: 2437
Reputation: 362707
An iterator is iterable.
That's documented and explained here:
Iterators are required to have an
__iter__()
method that returns the iterator object itself so every iterator is also iterable
An iterable is not necessarily an iterator
Iterators must have a __next__
method, by definition. To give a simple counterexample:
>>> ''.__next__
AttributeError: 'str' object has no attribute '__next__'
A string object is an iterable, but is not an iterator.
Upvotes: 1
Reputation: 4296
Yes. All iterators have an __iter__
method that returns itself. From the docs
iterator.__iter__()
Return the iterator object itself. This is required to allow both containers and iterators to be used with the for and in statements.
Upvotes: 0
Reputation: 78556
An iterator is iterable. And yes, an iterator always has an __iter__
method.
Calling iter
on an iterator, which summons the __iter__
hook, returns the same iterator:
>>> it = iter([]) # return iterator from iterable
>>> it is iter(iter(it)) is it.__iter__().__iter__().__iter__()
True
A classical example of method chaining.
As you must have also noticed, most implementations of the iterator protocol for custom classes always follows:
def __iter__(self):
return self
That is if the iteration is not delegated to another iterator, via say return iter(...)
.
It would be quite counter-intuitive for an iterator to not implement the iterator protocol don't you think? The __iter__
implementation of the protocol is described below:
iterator.__iter__()
Return the iterator object itself. This is required to allow both containers and iterators to be used with the
for
andin
statements.
[Emphasis mine]
This behaviour is expectedly consistent with iterator objects returned by builtins:
>>> m = map(None, [])
>>> m
<map object at 0x...>
>>> m is m.__iter__().__iter__().__iter__()
True
P.S: I apologise for calling dunders repeatedly; makes it look like it's the right thing to do. But it's not!
Upvotes: 7
Reputation: 152647
An iterable needs to implement an __iter__
method or a __getitem__
method:
An object can be iterated over with
for
if it implements__iter__()
or__getitem__()
.
An iterator needs a __iter__
method (that returns self
) and a __next__
method (I'm not 100% sure about the __next__
).
__iter__
method?Yes!
This is also documented in the Data model:
object.__iter__(self)
This method is called when an iterator is required for a container. This method should return a new iterator object that can iterate over all the objects in the container. For mappings, it should iterate over the keys of the container.
Iterator objects also need to implement this method; they are required to return themselves. For more information on iterator objects, see Iterator Types.
(Emphasis mine)
As to your second question:
Yes, because it has a __iter__
method.
Besides the formal implementation it's easy to check if something is iterable by just checking if iter()
can be called on it:
def is_iterable(something):
try:
iter(something)
except TypeError:
return False
else:
return True
Likewise it's possible to check if something is an iterator by checking if iter()
called on something returns itself:
def is_iterator(something):
try:
return iter(something) is something # it needs to return itself to be an iterator
except TypeError:
return False
But don't use them in development code, these are just for "visualization". Mostly you just iterator over something using for ... in ...
or if you need an iterator you use iterator = iter(...)
and then process the iterator by calling next(iterator)
until it throws a StopIteration
.
Upvotes: 19