iterator
1. Iteratable object
from collections import Interable print(isinstance([11,22,33],Interable))
If you want an object to be iteratable, you must override__ iter__ Method, so that it can pass the test of interoperable, but it can not be traversed by the for function at this time, so it is only an iteratable object, not an iterator.
Example code:
from collections.abc import Iterable class ClassMate(): def __init__(self) -> None: self.name = list() def add(self,name): self.name.append(name) def __iter__(self): pass classmate = ClassMate() print("judge ClassMate Whether it is an iteratable object:",isinstance(classmate,Iterable))
2. Iterator
Iterators must override__ iter__ Methods and__ next__ Method, where__ iter__ Method must return a reference to an object.
Iterators can be traversed using the for loop, for temp in xxx_obj execution process:
- Judgment object xxx_obj Yes No__ iter__ Method (iteratable object)
- Under the condition that the first step holds, call the iter function to get the object xxx_obj__ next__ The return value of is an iterator
- Automatically call the next function of the iterator, that is, the next function of the iterator__ next__ Method until a StopIteration exception is thrown.
For such a for loop
for i in seq: do_something_to(i)
It actually works like this
fetch_iterator = iter(q) while True: try: i = fetch_iterator.next() except StopIteration: break do_something_to(i)
Iterators are very important. Dictionaries, files and lists in Python 3 are iteratable objects.
3. Write an iterative class
from collections.abc import Iterable from collections.abc import Iterator # The implementation will be an iteratable class class ClassMate(object): def __init__(self) -> None: self.names = list() def add(self,name): self.names.append(name) def __iter__(self): # Returns an instance object of an iterator return ClassIterator(self) class ClassIterator(object): def __init__(self,obj): self.obj = obj # Record the position of the previous pointer through the instance property self.current_num = 0 def __iter__(self): pass def __next__(self): """next Method to execute this method""" if self.current_num < len(self.obj.names): # Manual cross-border prevention ret = self.obj.names[self.current_num] self.current_num += 1 return ret else: raise StopIteration # The for loop automatically catches errors classmate = ClassMate() classmate.add('Xiao Wang') classmate.add('Xiaomei') classmate.add('Xiao Ming') class_iterator = iter(classmate) print("judge classmate Is it an iteratable object",isinstance(classmate,Iterable)) print("judge class_iterator Is it an iterator",isinstance(class_iterator,Iterator)) for name in classmate: print(name) # Output: # True to determine whether classmate is an iteratable object # Judge class_ Is iterator an iterator True # Xiao Wang # Xiaomei # Xiao Ming
Execution process:
be careful:
- Of iteratable object A__ iter__ Returns the instance object B of an iterator. When initializing iterator B, iteratable object A needs to be passed into the initialization method;
- The iterator instance object passes an instance property self.current_num records the current read position
- You need to manually prevent out of bounds, otherwise the for statement will continue to execute__ next__, And capture the returned None. At this time, the for loop will automatically capture by throwing a StopIteration error.
4. Encapsulate into a class
The above method uses two classes, which is a bit wasteful of resources. We encapsulate them all into one class
from collections.abc import Iterable from collections.abc import Iterator # The implementation will be an iteratable class class ClassMate(object): def __init__(self): self.names = list() self.current_count = 0 def add(self,name): self.names.append(name) def __iter__(self): # Returns its own instance object return self def __next__(self): if self.current_count<len(self.names): ret = self.names[self.current_count] self.current_count+=1 return ret else: raise StopIteration classmate = ClassMate() classmate.add('Xiao Wang') classmate.add('Xiaomei') classmate.add('Xiao Ming') class_iterator = iter(classmate) print("judge classmate Is it an iteratable object",isinstance(classmate,Iterable)) print("judge class_iterator Is it an iterator",isinstance(class_iterator,Iterator)) for name in classmate: print(name) # Output: # True to determine whether classmate is an iteratable object # Judge class_ Is iterator an iterator True # Xiao Wang # Xiaomei # Xiao Ming
5. Application of iterator
range and xrange
[supplement] the difference between range and xrange:
The difference between range and xrange: in python2, range returns a numeric value and xrange returns an iteratable object, which takes up a very small space,
In Python 3, range also returns an iteratable object.
Generating Fibonacci sequences using iterators
For example, you can use iterators to implement Fibonacci sequences
# General implementation a = 0 b = 1 i = 0 while i<10: a,b = b,a+b print(a)
# Iterator implementation class Fibonacci(object): def __init__(self,all_num): self.max_num = all_num self.count_num = 0 self.a = 0 self.b = 1 def __iter__(self): return self def __next__(self): if self.count_num < self.max_num: self.count_num += 1 self.a,self.b = self.b,self.a+self.b return self.a else: raise StopIteration fibo = Fibonacci(10) for num in fibo: print(num)
List parsing
List parsing, list complehensinos, comes from Haskell language and can replace some usage scenarios of lambda, map and filter functions.
Syntax [expr for iter_val in iterable if cond_expr]
Example 1: calculate the square of a sequence member
map(lambda x:x**2,range(6)) # perhaps [x**2 for x in range(6)]
Example 2: select odd numbers in seq sequence
filter(lambda x: x%2,seq) # or [x for x in seq if x%2]
Example 3: calculate the number of words in the text [list parsing supports multiple loops and multiple if statements, and the execution order is from left to right]
f = open('test.txt','r') len([word for line in f for word in line.split()])
The generator expression is similar to the list parsing expression: (expr for iter_val in iterable if cond_expr). Because the generator expression uses "lazy evaluation", it is more effective in memory than the list parsing expression.