Python learning notes: Generator walkthrough

Keywords: Python REST


1, List generation: the list can be generated dynamically instead of using fixed values to assign values to the list, so the program will be more flexible
def test(i):
    # Even number
    if i % 2 == 0:
        return i

# Ordinary generative
list1 = [i * 2 for i in range(10)]
print(list1)
# Select values through a function
list1 = [test(i) for i in range(10)]
print(list1)

2, Generator: the list is ready before calling. If the list has a large amount of data, it will always occupy memory and be inefficient,
For example, there is a list of 1 million elements. This cycle only circulates to the first 100 elements. The later elements are not used. Is there any one
Method can generate elements when it is called? This is the generator.

# (i * 2 for i in range(10000)) Returns the memory address of a generator
list3 = (i * 2 for i in range(10000))
Note: the generator cannot call the elements in the way of "list[0]", because the elements have not been generated at this time and can only be accessed by the for loop
# Can use__next()__Method to get the next, and the previous element disappears at the same time, so the generator only records the elements in the current position. You can't go back. Go ahead__next()__
print(list3.__next__())
print(list3.__next__())
print(list3.__next__())
# It's usually accessed in cycles, not in cycles__next__()Method
# That's how it works python Built in iterator with built-in next Method
for i in list3
  print(i)
For example, the Fibonacci sequence is generated by a generator (Fibonacci sequence definition: except for the first and second numbers, the following numbers are all the first two numbers you want to add)
The following common writing
list_num = (i for i in range(10))
list_new_num = []

for i in list_num:
    if i != 0 and i != 1:
        list_new_num.append(list_new_num[i - 1] + list_new_num[i - 2])
    else:
        list_new_num.append(i)
    print(list_new_num[i])
Another way to write Fibonacci series
n, a, b = 0, 0, 1  # continuous assignment
while n < 10:
    print(b)
    a, b = b, a + b
    n = n + 1
Change the code above.
The interrupt state of the function is saved by the yield keyword. The code that is called outside can be executed first without waiting for all the values to be calculated, which can greatly improve the efficiency
When next() is executed, return the position of yield to continue to execute the code inside the function.
def fib(max):
    n, a, b = 0, 0, 1

    while n < max:
        yield b  # Add yield It becomes a generator, equivalent to saving b Variable the value here. this b It's going to get outside, so it's going to use yield sign
        a,b = b,a+b
        n = n+1
    return "Error"  # This is the error message and will be caught by exception.

# Returns a generator, so fib Equivalent to the specific implementation of this generator.
g = fib(6)

while True:
    try:
        # this next It's a built-in method that works with__next()__Similarly, take out the next element of the generator
        # next Back in top fib Functional yield Location
        x = next(g)
        print("g:",x)
    except StopIteration as e:  # Catch exceptions here to end the program
        print("error:",e.value)
        break
Yield can also be used as the call of a single thread coroutine. Although it is still a single thread (thread and coroutine will be introduced separately later), yield can greatly improve efficiency
The following is a typical production and consumption model. One person produces, several people consume, and it is carried out at the same time. It also makes use of the characteristics of yield. We call it "parallel generator"
import time
def consumer(name):
    print("%s Ready to eat steamed buns!"%name)
    while True:
        baozi = yield # yield No return value, why assign to baozhi What about it?

        print("Steamed stuffed bun[%s]Coming, being[%s]Yes." % (baozi,name))

# c = consumer("tangwei")
# c.__next__() # First__next__Execute to consumer In function yield And back
# c.__next__() # The second "next" continues to execute the rest until the loop continues to execute until yield jumps out

# c.__next__() # First__next__Execute to consumer In function yield And back
# c.send("Meat stuffing") # send passes a value to the position of yield in the consumer function, that is, it assigns a value to the variable baozi and then next. Just calling "next" will not pass a value to yield

def producer(name):
    # Build 1 generator
    c1 = consumer("tangwei")
    # Build 1 generator
    c2 = consumer("chenyadan")
    # c1 Ready to eat steamed buns,__next__Execute to consumer In function yield And back
    c1.__next__()
    # C2 Ditto
    c2.__next__()
    print("I am a cook.[%s],I'm starting to make steamed buns..."%(name))
    for i in range(10):
        time.sleep(1)
        print("Made a bun, half a person..")
        c1.send(i) # send Pass a value to consumer In function yield The position assigned to the variable baozi,Call only__next__Not giving yield Passing value
        c2.send(i)

# Although the program is still executed in sequence, because the program flow can jump between functions, there is no need to wait for one function to finish before executing another function, which greatly improves the execution efficiency.
# This is the parallel effect of a single thread, that is, the coroutine, which is a smaller unit than the thread and lives in the thread.
producer("Go Believe")

Posted by ozone1 on Thu, 09 Apr 2020 05:52:26 -0700