Describes how to use the yield generator in Python3.
Any function that uses yield is called a generator, for example:
Def count (n): while n> 0: yield n # generated value: n-= 1
Another statement is that the generator is a function that returns the iterator. The difference from a common function is that the generator contains the yield statement. To put it simply, the generator is an iterator.
Yield allows the function to generate a sequence. The object type returned by the function is "generator", and the sequence value is returned by calling the next () method continuously through this object.
C = count (5) c. _ next _ () # use c. _ next _ () cannot use c. next () >>> 5 c. _ next _ () >>> 4
The generator function starts to execute the statements in the function only when the _ next () _ method is called. For example:
Def count (n): print ("cunting") while n> 0: yield n # generated value: n-= 1
When the count function is called: c = count (5), "counting" is not printed. The statement is actually executed only when c. _ next _ () is called. Each time the _ next _ () method is called, the count function runs until yield n of the statement, and the return value of __next _ () is the generated value n, when the _ next _ () method is called again, the function continues to execute statements after yield (a friend familiar with Java must know Thread. the yield () method is used to pause the running of the current thread and let other threads execute it), for example:
Def count (n): print ("cunting") while n> 0: print ('before yield ') yield n # generated value: n-= 1 print ('after yield ')
When the above Code calls the _ next _ method for the first time, it does not print "after yield ". If the _ next _ method is always called, the program reports an error when no value can be iterated is executed:
Traceback (most recent call last): File "", line 1, in StopIteration
Therefore, the for loop is generally used instead of calling the _ next _ method manually:
for i in count(5): print (i),
Example: Use the yield generator to simulate the command "tail-f file | grep python" in Linux to find the lines with the python character in the monitoring log file.
Import time def tail (f): f. seek () # Move to the file EOF while True: line = f. readline () # Read the new text line in the file if not line: time. sleep (0.1) continue yield line def grep (lines, searchtext): for line in lines: if searchtext in line: yield line flog = tail (open ('warn. log') pylines = grep (flog, 'python') for line in pylines: print (line,) # When this program is running, if. A new line is added at the end of the log file, and this line contains python, the line will be printed # If warn is enabled. log, there is already a line containing python at the end, and the line will not be printed, because the above is f. seek () moved to the file EOF # therefore, the above program implements tail-f warn. log | grep 'python' function, which dynamically detects warn in real time. whether a new line is added in log # And the line contains python
Use yield to implement the Fibonacci series:
def fibonacci(): a=b=1 yield a yield b while True: a,b = b,a+b yield b
Call:
for num in fibonacci(): if num > 100: break print (num),
The role of return in yield:
As a generator, because a value is returned for each iteration, it cannot be displayed to return a value in the generator function, including the None value. Otherwise, a "SyntaxError" exception will be thrown, however, a separate return statement can appear in the function to end the statement.
An example of preventing memory overflow during one-time reading through a fixed-length buffer:
def read_file(path): size = 1024 with open(path,'r') as f: while True: block = f.read(SIZE) if block: yield block else: return
If a specific value is returned in the function, an exception is thrown directly.
>>> def test_return(): ... yield 4 ... return 0 ... File "<stdin>", line 3 SyntaxError: 'return' with argument inside generator
Example
Here are some sample codes:
Example 1:
>>> Def mygenerator ():... print 'start... '... yield 5... >>> mygenerator () // called here, and no start... is printed... it indicates that the yield function is not run, that is, the <generator object mygenerator at 0xb762502c >>> mygenerator (). next () // call next () to run the function. start... 5 >>>
If multiple yield instances exist in a function, next () stops before the next yield instance. See Example 2:
Example 2:
>>> Def fun2 ():... print 'first '... yield 5... print 'second '... yield 23... print 'end... '... >>> g1 = fun2 () >>> g1.next () // first run, pause in yield 5 first 5 >>> g1.next () // second run, pause at yield 23 second 23 >>> g1.next () // The third run. Because there is no yield later, the next () will throw an error end... traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration>
Why does yield 5 output 5 and yield 23 output 23?
We assume that yield is an expression and the returned value exists.
Can I assume that the returned value of yield 5 must be 5? In fact, this is not the case. This function has a certain relationship with the send function, which is essentially similar to next (). The difference is that send is used to pass the value of the yield expression, however, next cannot pass a specific value, but can only pass None. Therefore, g. next () and g. send (None) is the same. See example 3:
Example 3:
>>> Def fun ():... print 'start... '... m = yield 5... print m... print 'midddle... '... d = yield 12... print d... print 'end... '... >>> m = fun () // create an object >>> m. next () // execute the function to start before the next yield... 5 >>> m. send ('message') // use send () to pass the value message // send () to pass in the middle... 12 >>> m. next () None // visible next () The returned value is null end... traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration