user-defined iterables as they do on built-in types as wellx squares( iter(xnext( next( more omitted next( next(istopiteration iterate manuallywhat loops do iter calls __iter__ next calls __next__ (in xcan catch this in try statement an equivalent coding of this iterable with __getitem__ might be less naturalbecause the for would then iterate through all offsets zero and higherthe offsets passed in would be only indirectly related to the range of values produced ( would need to map to start stopbecause __iter__ objects retain explicitly managed state between next callsthey can be more general than __getitem__ on the other handiterables based on __iter__ can sometimes be more complex and less functional than those based on __getitem__ they are really designed for iterationnot random indexing--in factthey don' overload the indexing expression at allthough you can collect their items in sequence such as list to enable other operationsx squares( [ typeerror'squaresobject does not support indexing list( )[ single versus multiple scans the __iter__ scheme is also the implementation for all the other iteration contexts we saw in action for the __getitem__ method--membership teststype constructorssequence assignmentand so on unlike our prior __getitem__ examplethoughwe also need to be aware that class' __iter__ may be designed for single traversal onlynot many classes choose scan behavior explicitly in their code for examplebecause the current squares class' __iter__ always returns self with just one copy of iteration stateit is one-shot iterationonce you've iterated over an instance of that classit' empty calling __iter__ again on the same instance returns self againin whatever state it may have been left you generally need to make new iterable instance object for each new iterationx squares( [ for in [ [ for in [make an iterable with state exhausts items__iter__ returns self now it' empty__iter__ returns same self iterable objects__iter__ and __next__