나는 현재 파이썬 요리 책을 읽고 있으며 현재 발전기를보고 있습니다. 머리를 돌리기가 어렵다.
Java 배경에서 왔을 때 Java에 해당하는 것이 있습니까? 이 책은 ‘프로듀서 / 소비자’에 대해 이야기하고 있었지만 스레딩에 대한 생각을 들었습니다.
발전기 란 무엇이며 왜 사용 하시겠습니까? 어떤 책도 인용하지 않고 분명히 (책에서 직접적이고 알맞은 대답을 찾을 수 없다면). 관대 한 느낌이 든다면 아마도 예가있을 것입니다!
답변
참고 :이 게시물은 Python 3.x 구문을 가정합니다. †
발전기는 단순히 당신이 호출 할 수있는 객체를 반환하는 함수입니다 next
그것이 제기 할 때까지 모든 호출 것이, 어떤 값을 반환 등 StopIteration
모든 값이 생성 된 것을 신호, 예외를. 이러한 객체를 반복 자라고합니다 .
일반 함수 return
는 Java와 마찬가지로을 사용하여 단일 값을 반환합니다 . 그러나 파이썬에는이라는 대안이 yield
있습니다. yield
함수의 어느 곳에서나 사용 하면 생성기가됩니다. 이 코드를 준수하십시오.
>>> def myGen(n):
... yield n
... yield n + 1
...
>>> g = myGen(6)
>>> next(g)
6
>>> next(g)
7
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
당신이 볼 수 있듯이, myGen(n)
산출하는 기능입니다 n
및 n + 1
. 모든 next
값 을 산출 할 때까지 모든 호출 은 단일 값을 산출합니다. for
루프 next
는 백그라운드에서 호출 되므로 다음과 같습니다.
>>> for n in myGen(6):
... print(n)
...
6
7
마찬가지로 특정 일반적인 유형의 생성기를 간결하게 설명하는 수단을 제공하는 생성기 표현식 이 있습니다 .
>>> g = (n for n in range(3, 5))
>>> next(g)
3
>>> next(g)
4
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> lc = [n for n in range(3, 5)]
>>> lc
[3, 4]
생성기 객체는 한 번 생성 되지만 해당 코드는 한 번에 실행 되지 않습니다 . next
실제로 코드를 실행 (일부)하는 호출 만 가능합니다 . yield
명령문에 도달 하면 생성기에서 코드 실행이 중지 되고 값이 리턴됩니다. 다음에 호출 next
하면 생성기가 마지막 이후에 남아있는 상태에서 실행이 계속됩니다 yield
. 이는 정규 함수와의 근본적인 차이점입니다. 즉, “상단”에서 실행을 시작하고 값을 반환하면 상태를 버립니다.
이 주제에 관해 할 말이 더 있습니다. 예를 들어 send
생성기로 다시 데이터를 보내는 것이 가능합니다 ( 참조 ). 그러나 그것은 발전기의 기본 개념을 이해할 때까지 살펴 보지 말 것을 제안하는 것입니다.
이제 물어볼 수 있습니다 : 왜 발전기를 사용합니까? 몇 가지 좋은 이유가 있습니다.
- 특정 개념은 생성기를 사용하여 훨씬 간결하게 설명 할 수 있습니다.
- 값 목록을 반환하는 함수를 만드는 대신 값을 즉시 생성하는 생성기를 작성할 수 있습니다. 이것은리스트를 구성 할 필요가 없다는 것을 의미하며, 결과 코드는 메모리 효율성이 높다는 것을 의미합니다. 이러한 방식으로 메모리에 맞추기에는 너무 큰 데이터 스트림을 설명 할 수도 있습니다.
-
생성기는 무한 스트림 을 자연스럽게 표현할 수있는 방법을 제공 합니다. 예를 들어 피보나치 수를 고려하십시오 .
>>> def fib(): ... a, b = 0, 1 ... while True: ... yield a ... a, b = b, a + b ... >>> import itertools >>> list(itertools.islice(fib(), 10)) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
이 코드는
itertools.islice
무한 스트림에서 유한 요소 수를 가져 오는 데 사용 됩니다.itertools
고급 생성기를 작성하기위한 필수 도구이므로 모듈 의 기능을 잘 살펴 보는 것이 좋습니다 .
† Python <= 2.6 정보 : 위의 예 에서 지정된 객체 next
의 메서드를 호출하는 함수입니다 __next__
. 파이썬 <2.6 용도, 즉 하나는 약간 다른 기술 = o.next()
대신이 next(o)
. Python 2.7에는 next()
호출이 .next
있으므로 2.7 에서 다음을 사용할 필요가 없습니다.
>>> g = (n for n in range(3, 5))
>>> g.next()
3
답변
생성기는 실제로 완료되기 전에 (데이터)를 반환하는 함수이지만 해당 시점에서 일시 중지되며 해당 시점에서 함수를 다시 시작할 수 있습니다.
>>> def myGenerator():
... yield 'These'
... yield 'words'
... yield 'come'
... yield 'one'
... yield 'at'
... yield 'a'
... yield 'time'
>>> myGeneratorInstance = myGenerator()
>>> next(myGeneratorInstance)
These
>>> next(myGeneratorInstance)
words
등등. 생성기 (또는 하나)의 이점은 한 번에 하나의 데이터를 처리하기 때문에 대량의 데이터를 처리 할 수 있다는 것입니다. 목록을 사용하면 과도한 메모리 요구 사항이 문제가 될 수 있습니다. 목록과 마찬가지로 생성기는 반복 가능하므로 동일한 방식으로 사용할 수 있습니다.
>>> for word in myGeneratorInstance:
... print word
These
words
come
one
at
a
time
예를 들어 생성기는 무한대를 처리하는 다른 방법을 제공합니다.
>>> from time import gmtime, strftime
>>> def myGen():
... while True:
... yield strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())
>>> myGeneratorInstance = myGen()
>>> next(myGeneratorInstance)
Thu, 28 Jun 2001 14:17:15 +0000
>>> next(myGeneratorInstance)
Thu, 28 Jun 2001 14:18:02 +0000
제너레이터는 무한 루프를 캡슐화하지만 요청할 때마다 각 답변을 얻으므로 문제가되지 않습니다.
답변
우선, 생성기 라는 용어 는 원래 파이썬에서 다소 잘못 정의되어 많은 혼란을 초래했습니다. 아마도 반복자 와 이터 러블을 의미 할 것입니다 ( 여기 참조 ). 그런 다음 파이썬에는 생성기 함수 (생성기 객체를 반환), 생성기 객체 (반복자) 및 생성기 표현식 (생성기 객체로 평가)이 있습니다.
제너레이터 용어집 에 따르면 이제 공식 용어는 제너레이터 가 “제너레이터 기능”의 줄임말 인 것으로 보입니다 . 과거에는 문서가 용어를 일관성없이 정의했지만 다행스럽게도이 용어는 수정되었습니다.
더 구체적으로 지정하지 않고 “발전기”라는 용어를 사용하지 않는 것이 좋습니다.
답변
제너레이터는 이터레이터를 만들기위한 속기라고 생각할 수 있습니다. 그것들은 Java Iterator처럼 동작합니다. 예:
>>> g = (x for x in range(10))
>>> g
<generator object <genexpr> at 0x7fac1c1e6aa0>
>>> g.next()
0
>>> g.next()
1
>>> g.next()
2
>>> list(g) # force iterating the rest
[3, 4, 5, 6, 7, 8, 9]
>>> g.next() # iterator is at the end; calling next again will throw
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
이것이 도움이 되길 바랍니다.
최신 정보:
다른 많은 답변이 보여주는 것처럼 생성기를 만드는 다른 방법이 있습니다. 위의 예제와 같이 괄호 구문을 사용하거나 yield를 사용할 수 있습니다. 또 다른 흥미로운 특징은 제너레이터가 “무한”할 수 있다는 것입니다.
>>> def infinite_gen():
... n = 0
... while True:
... yield n
... n = n + 1
...
>>> g = infinite_gen()
>>> g.next()
0
>>> g.next()
1
>>> g.next()
2
>>> g.next()
3
...
답변
이에 상응하는 Java는 없습니다.
다음은 약간의 고려 된 예입니다.
#! /usr/bin/python
def mygen(n):
x = 0
while x < n:
x = x + 1
if x % 3 == 0:
yield x
for a in mygen(100):
print a
생성기에는 0에서 n까지 실행되는 루프가 있으며 루프 변수가 3의 배수이면 변수가 생성됩니다.
for
루프가 반복 될 때마다 발전기가 실행됩니다. 생성기가 처음으로 실행되면 처음부터 시작하고 그렇지 않으면 이전에 생성 한 시간부터 계속됩니다.
답변
나는 프로그래밍 언어와 컴퓨팅에 대한 적절한 배경을 가진 사람들에게 스택 프레임 측면에서 생성기를 설명하고 싶습니다.
많은 언어에서 스택은 현재 스택 “프레임”입니다. 스택 프레임에는 해당 함수에 전달 된 인수를 포함하여 함수에 로컬 인 변수에 할당 된 공간이 포함됩니다.
함수를 호출하면 현재 실행 지점 ( “프로그램 카운터”또는 이와 동등한 기능)이 스택으로 푸시되고 새 스택 프레임이 생성됩니다. 그런 다음 실행은 호출되는 함수의 시작 부분으로 전송됩니다.
일반 함수를 사용하면 어느 시점에서 함수가 값을 반환하고 스택이 “팝핑”됩니다. 함수의 스택 프레임이 삭제되고 이전 위치에서 실행이 재개됩니다.
함수가 제너레이터 인 경우 yield 문을 사용하여 스택 프레임을 버리지 않고 값 을 반환 할 수 있습니다 . 함수 내의 지역 변수 값과 프로그램 카운터는 유지됩니다. 따라서 yield 문에서 실행을 계속하면서 생성기를 나중에 다시 시작할 수 있으며 더 많은 코드를 실행하고 다른 값을 반환 할 수 있습니다.
Python 2.5 이전에는 모든 생성자가 수행했습니다. 파이썬 2.5 다시 값을 전달하는 기능이 추가 의 발생기로도있다. 이렇게하면 전달 된 값은 생성기에서 제어 (및 값)를 일시적으로 리턴 한 yield 문에서 발생하는 표현식으로 사용할 수 있습니다.
생성기의 주요 장점은 스택 프레임을 폐기 할 때마다 일반 상태와 달리 함수의 “상태”가 유지된다는 것입니다. 두 번째 이점은 일부 기능 호출 오버 헤드 (스택 프레임 생성 및 삭제)를 피할 수 있다는 것입니다.
답변
Stephan202의 답변에 추가 할 수있는 유일한 것은 David Beazley의 PyCon ’08 프레젠테이션 “시스템 프로그래머를위한 생성자 트릭”을 보도록 권장하는 것입니다. 어딘가에. 이것은 “Python looks fun”에서 “이것이 내가 찾던 것”으로 나를 데려 간 것입니다. 그것은에서의 http://www.dabeaz.com/generators/ .