Home  >  Article  >  Backend Development  >  Introduction to the usage of yield keyword in python (code example)

Introduction to the usage of yield keyword in python (code example)

不言
不言forward
2018-12-15 10:09:442486browse

This article brings you an introduction to the usage of the yield keyword in python (code examples). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

yield is a keyword of python. When I first came into contact with python, I had only a little understanding of this keyword. After mastering it, I realized that this keyword is very useful. This article will sort out how to use yield. .

1 Use yield to create a generator

In python, a generator is an iterable object, but an iterable object is not necessarily a generator.
For example, list is an iterable object

>>> a = list(range(3))
>>> for i in a:
    print(i)
0
1
2
3

But all the values ​​of a list object are stored in memory. If the amount of data is very large, the memory may not be enough; in this case For example, Python can use "()" to construct a generator object:

>>> b = (x for x in range(3))
>>> for i in b:
    print(i)

0
1
2
>>> for i in b:
    print(i)
    
>>>

The generator can be iterated, and the data is generated in real time and will not all be saved in memory; it is worth noting Yes, The generator can only read once. As you can see from the above running results, the result output by the second for loop is empty.

In actual programming, if a function needs to generate a piece of serialized data, the simplest way is to put all the results in a list and return it. If the amount of data is large, you should consider using a generator To rewrite a function that directly returns a list (Effective Python, Item 16).

>>> def get_generator():
    for i in range(3):
        print('gen ', i)
        yield i
        
>>> c = get_generator()    
>>> c = get_generator()
>>> for i in c:
    print(i)
    
gen  0
0
gen  1
1
gen  2
2

As can be seen from the above code, when the get_generator function is called, the code inside the function will not be executed, but a Iterator object, the code in the function will be executed only when iterating with a for loop.
In addition to using the for loop to obtain the value returned by the generator, you can also use next and send

>>> c = get_generator()
>>> print(next(c))
gen  0
0
>>> print(next(c))
gen  1
1
>>> print(next(c))
gen  2
2
>>> print(next(c))
Traceback (most recent call last):
  File "<pyshell#59>", line 1, in <module>
    print(next(c))
StopIteration
>>> c = get_generator()
>>> c.send(None)
gen  0
0
>>> c.send(None)
gen  1
1
>>> c.send(None)
gen  2
2
>>> c.send(None)
Traceback (most recent call last):
  File "<pyshell#66>", line 1, in <module>
    c.send(None)
StopIteration

After the result of the generator is read, a StopIteration exception will be generated

2 Using yield in coroutines

A common usage scenario is to implement coroutines through yield. Take the following producer-consumer model as an example:

# import logging
# import contextlib
# def foobar():
#     logging.debug('Some debug data')
#     logging.error('Some error data')
#     logging.debug('More debug data')
# @contextlib.contextmanager
# def debug_logging(level):
#     logger = logging.getLogger()
#     old_level = logger.getEffectiveLevel()
#     logger.setLevel(level)
#     try:
#         yield
#     finally:
#         logger.setLevel(old_level)
# with debug_logging(logging.DEBUG):
#     print('inside context')
#     foobar()
# print('outside context')
# foobar()
def consumer():
    r = 'yield'
    while True:
        print('[CONSUMER] r is %s...' % r)
        #当下边语句执行时,先执行yield r,然后consumer暂停,此时赋值运算还未进行
        #等到producer调用send()时,send()的参数作为yield r表达式的值赋给等号左边
        n = yield r #yield表达式可以接收send()发出的参数
        if not n:
            return # 这里会raise一个StopIteration
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'
def produce(c):
    c.send(None)
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)   #调用consumer生成器
        print('[PRODUCER] Consumer return: %s' % r)
    c.send(None)    
    c.close()
c = consumer()
produce(c)
[CONSUMER] r is yield...
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
Traceback (most recent call last):
  File ".\foobar.py", line 51, in <module>
    produce(c)
  File ".\foobar.py", line 47, in produce
    c.send(None)
StopIteration

As can be seen in the above example, the yield expression and send can be used to exchange data.

n = yield r
r = c.send(n)

3 Used in contextmanager

In addition A more interesting usage scenario is in contextmanager, as follows:

import logging
import contextlib
def foobar():
    logging.debug('Some debug data')
    logging.error('Some error data')
    logging.debug('More debug data')
@contextlib.contextmanager
def debug_logging(level):
    logger = logging.getLogger()
    old_level = logger.getEffectiveLevel()
    logger.setLevel(level)
    try:
        yield #这里表示with块中的语句
    finally:
        logger.setLevel(old_level)
with debug_logging(logging.DEBUG):
    print('inside context')
    foobar()
print('outside context')
foobar()
inside context
DEBUG:root:Some debug data
ERROR:root:Some error data
DEBUG:root:More debug data
outside context
ERROR:root:Some error data

In the above code, the log level is temporarily increased by using the context manager (contextmanager), and yield represents the statement in the with block;

Summary

The yield expression can create a generator, you should consider using a generator to rewrite the function that directly returns the list;

Since the generator only It can be read once, so pay special attention when using a for loop to traverse; if the generator continues to read after reading, it will raise a StopIteration exception. In actual programming, this exception can be used as a basis for judging the termination of reading;

A common usage scenario of yield is to implement coroutines; by cooperating with the send function, it can achieve the effect of exchanging data;

yield can also be expressed in the function modified by contextmanager in the with block Statement

The above is the detailed content of Introduction to the usage of yield keyword in python (code example). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete