2023-05-03 11:06:20 +02:00
== Why is this an issue?
2021-04-28 16:49:39 +02:00
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".
2021-04-28 18:08:03 +02:00
2023-05-03 11:06:20 +02:00
=== Noncompliant code example
2021-04-28 16:49:39 +02:00
2022-02-04 17:28:24 +01:00
[source,python]
2021-04-28 16:49:39 +02:00
----
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)
----
2021-04-28 18:08:03 +02:00
2023-05-03 11:06:20 +02:00
=== Compliant solution
2021-04-28 16:49:39 +02:00
2022-02-04 17:28:24 +01:00
[source,python]
2021-04-28 16:49:39 +02:00
----
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)
----
2021-04-28 18:08:03 +02:00
2023-05-03 11:06:20 +02:00
== Resources
2021-04-28 16:49:39 +02:00
* 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]
2021-04-28 18:08:03 +02:00
2021-06-02 20:44:38 +02:00
2021-06-03 09:05:38 +02:00
ifdef::env-github,rspecator-view[]
2021-09-20 15:38:42 +02:00
'''
== Implementation Specification
(visible only on this page)
2023-05-25 14:18:12 +02:00
=== Message
* Add an __iter__ method to this class.
* Return "self" from this "__iter__" method.
=== Highlighting
* If the ++__iter__++ method is present but does not return "self"
** Primary: The ++__iter__++ method signature
** Secondary: The returned value if there is one
* If there is no ++__iter__++ method
** Primary: The class signature
** Secondary: The ++__next__++ method signature
2021-09-20 15:38:42 +02:00
2021-06-08 15:52:13 +02:00
'''
2021-06-02 20:44:38 +02:00
== Comments And Links
(visible only on this page)
2023-05-25 14:18:12 +02:00
=== relates to: S2876
2021-06-03 09:05:38 +02:00
endif::env-github,rspecator-view[]