생성기 개념
생성기는 결과를 시리즈로 저장하지 않지만 생성기의 상태를 저장하고 StopIteration 예외가 발생할 때까지 반복할 때마다 값을 반환합니다.
생성기 구문
생성기 표현식: 목록 분석 구문은 동일하지만 목록 분석의 []를 ()로 대체
생성기 표현식이 할 수 있는 것은 목록 분석 기본적으로 처리할 수 있으며, 그러나 처리할 시퀀스가 상대적으로 클 경우 목록 구문 분석은 더 많은 메모리를 소비합니다.
>>> gen = (x**2 for x in range(5))
>>> gen
<0x0000000002FB7B40> ;
>>> for g in gen:
... print(g, end='-')
...
0-1-4-9-16-
>>> for x in [0,1,2,3,4,5]:
... print(x, end='-')
...
0-1-2-3-4-5-
생성기 함수: 함수에 항복 키워드가 나타나면 해당 함수는 더 이상 일반 함수가 아니라 생성기 함수입니다.
그러나 생성기 기능은 무제한 시퀀스를 생성할 수 있으므로 목록을 전혀 처리할 수 없습니다.
Yield의 기능은 함수를 생성기로 바꾸는 것입니다. Yield가 있는 함수는 더 이상 일반 함수가 아니며 Python 인터프리터는 이를 생성기로 처리합니다.
다음은 홀수를 무한히 생성할 수 있는 생성 함수입니다.
def 홀수():
n=1
True:
산출 n
n+=2
odd_num = 홀수()
count = 0
for o in 홀수_숫자:
if count >=5: break
print(o)
count +=1
물론 비슷한 작업을 수동으로 수행할 수 있습니다. 반복자 작성 그 효과는 생성기가 더 직관적이고 이해하기 쉽다는 것입니다
class Iter:
def __init__(self):
self.start=-1
def __iter__(self ):
return self
def __next__(self):
self.start +=2
return self.start
I = Iter()
범위 내 계산(5) :
print( next(I))
여담: 생성기에는 __iter() 및 next__() 메서드가 포함되어 있으므로 for를 직접 사용하여 반복할 수 있지만 자체 작성은 없습니다. StopIteration을 포함하는 Iter는 수동 루핑을 통해서만 수행할 수 있습니다.
>>> from collections import Iterable
>>>>>isinstance(odd_num, Iterator)
True
>> ; iter(odd_num)는odd_num
True
>>> help(odd_num)
생성기 개체에 대한 도움말:
odd = class Generator(object)
| 여기에 정의됨:
|
| __iter__(self, /)
| iter(self )를 구현합니다.
|
| __next__(self, /)
| .
...
위 결과를 보면 이제 Iterator 메서드에 따라 자신있게 반복할 수 있습니다!
... 1을 산출합니다
...>>> g=g1()
>>> g), Yield 문을 실행한 후 중단되므로 현재 프로그램 실행이 종료되지 않았습니다.
1
>>> next(g) # 프로그램은 Yield 문의 다음 문에서 실행을 시작하려고 시도하고 끝에 도달했음을 확인하므로 StopIteration 예외가 발생합니다.
추적(가장 최근 호출 마지막):
파일 "
StopIteration
>>>
반환이 발생하면 실행 중에 반환이 발생하면 StopIteration이 직접 발생하여 반복을 종료합니다.
>>> def g2():
... 'a'를 산출
... 반환
... 'b'를 산출
...
>>> g=g2()
>>> next(g) # 프로그램은 Yield 'a' 문을 실행한 후에도 해당 위치에 유지됩니다.
'a'
>>> next(g) # 프로그램은 다음 명령문이 반환됨을 확인하므로 StopIteration 예외가 발생하므로 항복 'b' 문은 실행되지 않습니다.
추적(가장 최근 호출 마지막):
파일 "
StopIteration
반환 후 값이 반환되는 경우 이면 이 값은 프로그램의 반환 값이 아니라 StopIteration 예외에 대한 설명입니다.
생성기가 return을 사용하여 값을 반환할 수 있는 방법은 없습니다.
>>> def g3():
... 'hello'를 반환합니다
... 'world'를 반환합니다
...
>> > g=g3()
>>> next(g)
'hello'
>>> next(g)
추적(가장 최근 호출):
파일 "
StopIteration: world
생성기가 지원하는 메서드
>>> ; help(odd_num)
생성기 개체에 대한 도움말:
odd = class Generator(object)
| 여기에 정의된 메서드:
......
| ..)
| close() -> 생성기 내부에서 GeneratorExit를 발생시킵니다.
|
| send(...)
| send(arg) ->
| 다음 반환 값을 반환하거나 StopIteration을 높입니다.
|
| throw(...)
| throw(typ[,val[,tb]]) ->
| 다음 산출 값을 반환하거나 StopIteration을 높입니다.
......
close()
수동으로 생성기 함수를 닫고 후속 호출이 수행됩니다. 직접 StopIteration 예외를 반환합니다.
>>> def g4():
... 1을 산출
... 2를 산출
... 3을 산출
...
>>>g=g4()
>>>다음(g)
1
>>g.close()
>> ; next(g) # 닫은 후에는 Yield 2 및 Yield 3 문이 더 이상 작동하지 않습니다.
추적(가장 최근 호출 마지막):
파일 "
StopIteration
send()
생성기 함수의 가장 큰 특징은 외부 변수를 받아들이고 변수 내용을 기반으로 결과를 계산한 후 반환할 수 있다는 점입니다.
제너레이터 함수에 대해 가장 이해하기 어려운 부분이자, 나중에 이야기할 코루틴의 구현이 이에 달려 있는 부분이기도 합니다.
def gen():
value=0
while True:
receive=yield value
if receive=='e':
value = 'got: % s' % 수신
g=gen()
print(g.send(None))
print(g.send('aaa'))
print( g.send( 3))
print(g.send('e'))
이때, Yield 문은 실행되었으나, receive에는 값이 할당되지 않았습니다.
수익률 값은 초기 값 0을 출력합니다
참고: 생성기 기능을 시작할 때만 (없음)을 보낼 수 있습니다. 다른 값을 입력하려고 하면 오류 메시지가 표시됩니다.
이때 Yield 값은 "got: aaa"를 출력한 후 멈춥니다.
최종 실행 결과는 다음과 같습니다.
got: aaa
got: 3
Traceback(가장 최근 호출 마지막):
파일 "h.py" , 14행,
print(g.send('e'))
StopIteration
throw() 이후에는 직접 예외가 발생하여 프로그램이 종료되거나, 산출량이 소비되거나, 다음 산출량이 없을 때 프로그램 종료로 직접 진행됩니다.
def gen():
while True:
try:
Yield '정상 값'
Yield '정상 값 2'
print('here')
제외 ValueError ; .throw(ValueError))
print(next(g))
print(g.throw(TypeError))
출력 결과는 다음과 같습니다:
normal 값
여기에서 ValueError가 발생했습니다
정상 값
정상 값 2
파일 "h.py", 15행, <모듈>
print (g.throw(TypeError))StopIteration
설명:
print(next(g)): 일반 값이 출력되고 Yield 'normal'을 유지합니다. 값 2 '이전.
g.throw(ValueError)가 실행되었으므로 이후의 모든 try 문을 건너뛰게 되는데, 이는 Yield 'normal value 2'가 실행되지 않는다는 의미이며, 그 후 Except 문을 입력하고 인쇄합니다. 여기에 ValueError가 있습니다.
print(next(g)) 는 Yield 'normal value 2' 문을 실행하고 문 실행 후 해당 위치에 유지됩니다.
g.throw(TypeError): try 문에서 빠져나오므로 print('here')가 실행되지 않습니다. 그런 다음 break 문을 실행하고 while 루프에서 빠져나옵니다. 그런 다음 프로그램 끝에 도달하므로 StopIteration 예외가 발생합니다.
다음은 다차원 목록을 확장하거나 다차원 목록을 평면화하는 포괄적인 예입니다.)
def flatten(nested):
#문자열인 경우 수동으로 TypeError를 발생시킵니다.
if isinstance(nested, str):raise TypeError
for sublist innested: for element in flatten(sublist):
#yield 요소
인쇄('Got:' , Element)
Typeerror 제외:
#Print ('Here')
Yield Nested
L = ['AAADF' ,3],2,4,[5,[6, [8,[9]],'ddf'],7]]
for num in flatten(L):
print(num)
조금 어렵다면 이해하세요. 인쇄문의 주석을 열어서 보는 것이 더 명확할 것입니다.
yield from
yield에 의해 생성된 함수는 반복자이므로 일반적으로 루프 문에 넣어 결과를 출력합니다.
때로는 이 Yield에 의해 생성된 반복자를 다른 생성기 함수, 즉 생성기 중첩에 배치해야 합니다.
예:
def inner():
for i in range(10):Yield i
def external(): g_inner=inner( ) # 이것은 생성기입니다
while True:
res = g_inner.send(None)
g_outer=outer()
while True:
try :
print(g_outer.send(None))
Except StopIteration:
break
이때, Yield from 문을 사용하여 작업량을 줄일 수 있습니다.
def external2():
Yield from inner()
물론, Yield from 문의 초점은 내부와 외부 사이의 예외를 자동으로 처리하도록 돕는 것입니다. 레이어는 잘 작성된 기사 2개이므로 장황하게 설명하지 않겠습니다.
http://stackoverflow.com/questions/9708902/in-practice-what-are-the-main -uses-for-the-new-yield-from-syntax-in-python-3
요약
오리 모델 이론에 따르면 생성기는 일종의 반복자입니다. 반복을 사용하여 수행됩니다.
next(generator)가 처음 실행될 때 Yield 문 실행 후 프로그램이 일시 중지되고 모든 매개변수와 상태가 저장됩니다.
next(generator)가 다시 실행되면 Suspend 상태에서 실행됩니다.
코루틴 모델인 Generator.send(arg)를 통해 매개변수를 전달할 수 있습니다.
generator.throw(Exception)를 통해 예외를 전달할 수 있습니다. throw 문은 수율을 소비합니다.
generator.close()를 통해 생성기를 수동으로 닫을 수 있습니다.