>  기사  >  백엔드 개발  >  Python에서 Yield 키워드 사용법 소개(코드 예)

Python에서 Yield 키워드 사용법 소개(코드 예)

不言
不言앞으로
2018-12-15 10:09:442486검색

이 글은 Python에서 Yield 키워드의 사용법을 소개합니다(코드 예제). 필요한 친구들이 참고할 수 있기를 바랍니다.

yield는 Python의 키워드입니다. 처음 Python을 접했을 때 이 키워드에 대해 조금밖에 이해하지 못했는데, 익히고 나서 이 키워드가 매우 유용하다는 것을 깨달았습니다. . 이 글에서는 Yield를 사용하는 방법을 설명합니다.

1 Yield를 사용하여 생성기 만들기

Python에서 생성기는 반복 가능한 객체이지만 반복 가능한 객체가 반드시 생성기는 아닙니다.
예를 들어 리스트는 반복 가능한 객체입니다

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

하지만 리스트 객체의 모든 값은 메모리에 저장됩니다. 데이터 양이 너무 많으면 메모리가 부족할 수 있습니다. 이 경우 생성기를 사용할 수 있습니다. 예를 들어 Python은 "()"를 사용하여 생성기 개체를 생성할 수 있습니다.

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

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

생성기는 반복될 수 있으며 데이터는 실제로 생성됩니다. 위의 실행 결과에서 볼 수 있듯이 두 번째 for 루프의 결과 출력은 비어 있습니다. .

실제 프로그래밍에서 함수가 직렬화된 데이터 조각을 생성해야 하는 경우 가장 간단한 방법은 모든 결과를 목록에 넣고 데이터 양이 많으면 반환하는 것입니다. 목록을 직접 반환하는 함수를 다시 작성하려면 Generator를 사용하는 것이 좋습니다(Effective Python, 항목 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
위 코드에서 알 수 있듯이 get_generator 함수를 호출하면 함수 내부의 코드가 실행되지는 않지만 for 루프로 반복하면 함수의 코드가 실행됩니다.

for 루프를 사용하여 생성기가 반환한 값을 얻는 것 외에도 next를 사용하여 보낼 수도 있습니다

>>> 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

생성기의 결과를 읽은 후 StopIteration 예외가 생성됩니다.# 🎜🎜#

2 코루틴에서

yield를 사용하세요. 일반적인 사용 시나리오는 항복을 통해 코루틴을 구현하는 것입니다. 다음은 생산자입니다. 소비자 모델을 예로 들어보겠습니다:

# 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
위의 예에서 볼 수 있듯이, Yield 표현식과 send는 데이터를 교환하는 효과를 가질 수 있습니다.

n = yield r
r = c.send(n)
# 🎜🎜##🎜 🎜#3 Use in contextmanager

또 다른 흥미로운 사용 시나리오는 다음과 같이 contextmanager에 있습니다.

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
위 코드에서 다음을 사용하여 context 관리자(contextmanager)는 로그 수준을 높입니다. Yield는 with 블록의 명령문을 나타냅니다. 생성기를 생성할 때 목록을 직접 반환하는 함수를 다시 작성하는 것을 고려해야 합니다. 생성기는 한 번만 읽을 수 있으므로 for 루프를 사용하여 탐색할 때 특별한 주의를 기울여야 합니다. 계속해서 읽으면 실제 프로그래밍에서 이 예외가 발생할 수 있습니다. 읽기 종료를 판단하는 기준으로 사용됩니다.

yield 일반적인 사용 시나리오는 전송 기능을 사용하여 코루틴을 구현하는 것입니다.

# 🎜🎜#yield는 contextmanager

에 의해 수정된 함수의 with 블록에 있는 명령문을 나타낼 수도 있습니다.

위 내용은 Python에서 Yield 키워드 사용법 소개(코드 예)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제