For-in loops, yield from and
iterable unpacking only work with iterable objects. In order to be iterable, an
object should have either an __iter__ method or a __getitem__ method implementing the Sequence semantic.
Note also that iterating over an asynchronous iterable, i.e. an
object having the __aiter__ method, requires the use of async for ... in instead of for ...
in.
This rule raises an issue when a non iterable object is used in a for-in loop, in a yield from or when it is
unpacked.
class Empty:
pass
empty = Empty()
for a in empty: # Noncompliant
print(a)
a, b, c = empty # Noncompliant
print(*empty) # Noncompliant
[1, 2, 3, *empty] # Noncompliant
# yield from
def generator():
yield from Empty() # Noncompliant
# async generators
async def async_generator():
yield 1
a, *rest = async_generator() # Noncompliant
for a in async_generator(): # Noncompliant; "async" is missing before "for"
print(a)
class MyIterable:
def __init__(self, values):
self._values = values
def __iter__(self):
return iter(self._values)
my_iterable = MyIterable(range(10))
for a in my_iterable:
print(a)
a, b, *c = my_iterable
print(*my_iterable)
[1, 2, 3, *my_iterable]
# yield from
def generator():
yield from subgenerator()
def subgenerator():
yield 1
# async generators
async def async_generator():
yield 1
async for a in async_generator():
print(a)