The iterator object obj is obtained by the ITER (string or list) method, and then the elements in the sequence can be accessed by the next(obj) or obj.next() method. When there are no accessible elements in the container, the next(obj) or obj.next() method will throw a StopIteration exception to terminate the iterator.
>>> str1="abc" >>> a2=iter(str1) >>> type(a2) <class 'str_iterator'> >>> list1=[1,2,3] >>> a1=iter(list1) >>> type(a1) <class 'list_iterator'> >>> a1.__next__() 1 >>> next(a1) 2 >>> next(a1) 3 >>> next(a1) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration //Code to block exception: >>> try: ... next(a1) ... except StopIteration: ... print("There is no element to take!") ... forLoop traversal iterator taking elements >>> list1=[1,2,3] >>> a1=iter(list1) >>> for i in a1: ... i ... 1 2 3
Custom iterators: Rules for defining your own data
To use a class as an iterator, you need to implement two methods, iter() and next(), in the class
class MyRange: def __init__(self,n): self.id=0 self.n=n def __iter__(self): """Return iterator object""" return self def __next__(self): """Rules for implementing data""" if self.id<self.n: num=self.id self.id+=1 return num #num is the element taken every time else: return StopIteration #No data exception range1=MyRange(2) print(iter(range1)) #Execution result: < main. MyRange object at 0x000002286ee18588 > print(next(range1)) #Execution result: 0 print(next(range1)) #Execution result: 1 print(next(range1)) #Execution result: < class' stopiteration '>
If list elements can be calculated by some algorithm, can we continuously calculate the following elements during the cycle? This saves a lot of space by eliminating the need to create a complete list. In Python, this kind of calculation mechanism is called Generator.
>>> gen1=(x*x for x in range(3)) >>> gen1 <generator object <genexpr> at 0x0000024FE5AACE08> >>> type(gen1) <class 'generator'> >>> next(gen1) 0 >>> next(gen1) 1 >>> next(gen1) 4 >>> next(gen1) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
In the process of calling the generator to run, every time a yield is encountered, the function pauses and saves all current running information, returns the value of yield, and continues to run from the current position the next time the next() method is executed.
def odd(): print("step 1") yield 11 print("step 2") yield 22 o=odd() first=next(o) print(first) second=next(o) print(second) third=next(o) print(third) """Execution result: step 1 11 step 2 22 Traceback (most recent call last): File "E:\2019TestStudy\Fullday\6_List remainder, primitives, and dictionaries\a.py", line 12, in <module> third=next(o) StopIteration """ //Traversal execution function o1=odd() for i in o1: print(i) """Execution result: step 1 11 step 2 22 """
- Differences between iterators and generators:
(1) The iterator type can be customized by implementing the corresponding methods of iterator and next. For an iteratable object, the for statement can get the iterator through the iter() method, and the next element of the container through the next method.
(2) Generator is a special kind of iterator, which supports the generator protocol internally, and does not need to define the uiter uuuuu() and next() methods explicitly.
(3) Generators are generated by generator functions, which can be defined by normal def statements, but return one result at a time instead of return.