The https://www.python.org/dev/peps/pep-0234/#python-api-specification[iterator protocol] specifies that an iterator object should have

* a ``++__next__++`` method retrieving the next value or raising ``++StopIteration++`` when there are no more values left.
* an ``++__iter__++`` method which should always return ``++self++``. This enables iterators to be used as sequences in for-loops and other places.

This rule raises an issue when a class has a ``++__next__++`` method and either:

* it doesn't have an ``++__iter__++`` method.
* or its ``++__iter__++`` method does not return "self".


== Noncompliant Code Example

----
class MyIterator:  # Noncompliant. Class has a __next__ method but no __iter__ method

    def __init__(self, values):
        self._values = values
        self._index = 0

    def __next__(self):
        if self._index >= len(self._values):
            raise StopIteration()
        value = self._values[self._index]
        self._index += 1
        return value


class MyIterator:
    def __init__(self, values):
        self._values = values
        self._index = 0

    def __next__(self):
        if self._index >= len(self._values):
            raise StopIteration()
        value = self._values[self._index]
        self._index += 1
        return value

    def __iter__(self):
        return 42  # Noncompliant. This __iter__ method does not return self


class MyIterable:  # Ok. This is an iterable, not an iterator, i.e. it has an __iter__ method but no __next__ method. Thus __iter__ doesn't have to return "self"

    def __init__(self, values):
        self._values = values

    def __iter__(self):
        return MyIterator(self._values)
----


== Compliant Solution

----
class MyIterator:
    def __init__(self, values):
        self._values = values
        self._index = 0

    def __next__(self):
        if self._index >= len(self._values):
            raise StopIteration()
        value = self._values[self._index]
        self._index += 1
        return value

    def __iter__(self):
        return self

class MyIterable:
    def __init__(self, values):
        self._values = values

    def __iter__(self):
        return MyIterator(self._values)
----


== See

* https://www.python.org/dev/peps/pep-0234/#python-api-specification[PEP 234 - Iterators]
* https://docs.python.org/3/library/stdtypes.html#iterator-types[Python documentation - Iterator Types]

