iterator
iterable
An object with an __iter__ method is iterable, and they can all be evaluated using a for loop (this is not true, the __iter__ method should return an iterator).
E.g:
print('__iter__' in dir([])) # True print('__iter__' in dir(())) # True print('__iter__' in dir("wfdsf")) # True print ('__ iter__' in dir (123)) # False
iterator
An iterable object with an internal __next__ method is an iterator, and an iterator is a part of an iterable.
Iterable objects call __iter__() to form an iterator
ret = "adc".__iter__() ret2 = ret .__ iter __ () # view type print(type(ret)) # <class 'str_iterator'> # View the difference between an iterable and an iterator print(set(dir("abc".__iter__()))-set(dir("abc"))) # {'__next__', '__setstate__', '__length_hint__'} # See the difference between iterator and iterable object's __iter__ method print (ret == ret2) # True # Use the __next__ method to get the value from the iterator print(ret.__next__()) # a print(ret.__next__()) # b print(ret.__next__()) # c print(ret.__next__()) # Throws StopIteration exception #Use the while loop to implement the function of the for loop l = [1,2,3,4] l_iter = l .__ iter __ () while True: try: #handle exception item = l_iter.__next__() print(item) except StopIteration: break
Determine if an object is an iterator or an iterable
method one,
Determine whether the method __iter__ exists in the method of the variable, and the existence is iterable (unless you write a class to implement this method yourself)
Determine whether the method __next__ exists in the method of the variable, and the existence is an iterator (unless you write a class yourself that implements this method)
print('__iter__' in dir([1,2,3,4])) # True print('__next__' in dir([1,2,3,4])) # False
Method 2
Determine if an object is an iterator or an instance of an iterable object
from collections import Iterable # The class of the iterable object from collections import Iterator # iterator class print(isinstance([1,2,3,4],Iterable)) # True str_iter = [1,2,3,4].__iter__() print(isinstance(str_iter,Iterator)) # True print(isinstance([1,2,3,4],Iterator)) # False
Features of iterators
- lazy operation
- The value is taken from the front to the back, the process is irreversible and cannot be repeated
- save memory
Builder
The essence of generators is iterators
So generators have the characteristics of iterators, but generators are code written by ourselves
generator function
A function that contains the yield keyword is a generator function.
Yield can return values from functions for us, but yield is different from return. The execution of return means the end of the program. Calling the generator function will not get the specific value returned, but an iterable object. Every time you get the value of this iterable object, you can push the execution of the function and get a new return value. until the end of the function execution.
def generator_fun1(): # This function is a generator function yield 1 yield 2 x=genrator_fun1()#x is a generator print(type(x)) # <class 'generator'> print(x.__next__()) # 1 print(x.__next__()) # 2
Example of listening for appending at the end of a file:
#Listen to the example of appending at the end of the file def tail(): f = open('file','r',encoding='utf-8')#Open the file f.seek(0,2) move the cursor to the end while True: line = f.readline()#read content if line: #content is not empty yield line#returns the read content import time time.sleep(0.1) g = tail() for i in g: print(i.strip())
send method
The send method can pass data to the generator and return a yield value
def func(): a = yield 5 # The value of send will be received by the variable before yield, because the expression will first calculate the value on the right, and will not be executed later # So it is said that at least one yield can be sent, otherwise a TypeError exception will be thrown yield a g = func() num = g.__next__() print(num) # 5 num2 = g.send('alex') print(num2) # alex
Example of finding the average
def init(func): #Generator's pre-fire decorator def inner(*args,**kwargs): g = func(*args,**kwargs) #func = averager g.__next__() # Execute __next__() first return g return inner @init def averager(): # find the average total = 0.0 count = 0 average = None while True: term = yield average # return average, send value to term total += term # sum count += 1 # times average = total/count # average g_avg = averager() print(g_avg.send(10))#10 print(g_avg.send(30))#20
yield form usage
def func(): a = 'AB' b ='CD' yield from a# 相当于for i in a:yield i yield from b# 相当于for i in b:yield i # 'A','B','C','D' # returned 4 times g = func() for i in g: print(i)
generator expression
#list comprehension y = [1,2,3,4,5,6,7,8] x = [1,4,9,16,25,36,49,64] #Get a list x from list y x = [i*i for i in y]#List comprehension #generator expression #Replace the list comprehension [] with () to become a generator expression. l = ['鸡蛋%s'%i for i in range(10)] print(l)#List expression to get a list #Generator expression gets a generator laomuji = ('鸡蛋%s'%i for i in range(10)) for egg in laomuji: print(egg)
Using __iter__ in Object Orientation
The essence of the for loop is to call the __iter__() method of an object, get an iterator, use the __next__() method to get the value, and do exception handling. When we define our own class, we can also implement __iter__ by ourselves () method so that our object can be looped.
class For: def __init__(self,list): self.list = list def __iter__(self): for i in self.list: yield i l = For([1,2,3,4,5,6]) for i in l: print(i)
This method is used in the form component. When we loop the form instance, its __iter__ method loops through its field list, and the value yield will come