생성기 이해는 정확히 어떻게 작동합니까?


91

생성기 이해 기능은 무엇을합니까? 어떻게 작동합니까? 그것에 대한 튜토리얼을 찾을 수 없습니다.


1
명확하게 말하면, 이들의 언어 이름은 생성기 이해가 아니라 생성기 표현식 입니다.
ShadowRanger 2018

1
@ShadowRanger 2018 년 7 월 Python-dev 메일 링리스트에서 "Naming comprehension syntax" 에 대한 토론이 있습니다. 여기서는 일관성을 위해 "generator comprehensions"라고 부르는 임시적이지만 상당히 만장일치로 동의했습니다.
Aaron Hall

답변:


144

목록 이해력을 이해합니까? 그렇다면 생성기 표현식은 목록 이해력과 비슷하지만 관심있는 모든 항목을 찾아서 목록에 포장하는 대신 대기하고 표현식에서 각 항목을 하나씩 생성합니다.

>>> my_list = [1, 3, 5, 9, 2, 6]
>>> filtered_list = [item for item in my_list if item > 3]
>>> print(filtered_list)
[5, 9, 6]
>>> len(filtered_list)
3
>>> # compare to generator expression
... 
>>> filtered_gen = (item for item in my_list if item > 3)
>>> print(filtered_gen)  # notice it's a generator object
<generator object <genexpr> at 0x7f2ad75f89e0>
>>> len(filtered_gen) # So technically, it has no length
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'generator' has no len()
>>> # We extract each item out individually. We'll do it manually first.
... 
>>> next(filtered_gen)
5
>>> next(filtered_gen)
9
>>> next(filtered_gen)
6
>>> next(filtered_gen) # Should be all out of items and give an error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> # Yup, the generator is spent. No values for you!
... 
>>> # Let's prove it gives the same results as our list comprehension
... 
>>> filtered_gen = (item for item in my_list if item > 3)
>>> gen_to_list = list(filtered_gen)
>>> print(gen_to_list)
[5, 9, 6]
>>> filtered_list == gen_to_list
True
>>> 

생성기 표현식은 한 번에 하나의 항목 만 산출하면되므로 메모리 사용량을 크게 절약 할 수 있습니다. 생성기 표현식은 한 번에 하나의 항목을 가져 와서 해당 항목을 기반으로 많은 계산을 수행 한 다음 다음 항목으로 이동해야하는 시나리오에서 가장 적합합니다. 둘 이상의 값이 필요한 경우 생성기 표현식을 사용하여 한 번에 몇 개를 가져올 수도 있습니다. 프로그램이 진행되기 전에 모든 값이 필요한 경우 대신 목록 이해를 사용하십시오.


3
여기에 한 가지 질문이 있습니다. 결과를 얻기 위해 next (gen_name)을 사용했고 Python 3에서 작동했습니다. __next __ ()를 사용해야하는 특정 시나리오가 있습니까?
Ankit Vashistha

2
@AnkitVashistha 아니, 항상 사용하는 next(...)대신 .__next__()파이썬 3에
토드 스웰

@gotgenes @AnkitVashistha If you need more than one value, you can also use a generator expression and grab a few at a time. 이 사용법에 대한 예를 들어 주시겠습니까? 감사.
LittleZero

19

생성기 이해는 목록 이해의 게으른 버전입니다.

목록 대신 반복자를 반환한다는 점을 제외하면 목록 이해와 같습니다. 즉, 다음 요소를 생성하는 next () 메서드가있는 객체입니다.

목록 이해에 익숙하지 않은 경우 여기를 참조 하고 생성기의 경우 여기를 참조 하십시오 .


4

목록 / 생성자 이해는 기존 목록에서 새 목록 / 생성자를 만드는 데 사용할 수있는 구성입니다.

1부터 10까지 각 숫자의 제곱 목록을 생성한다고 가정 해 보겠습니다. Python에서이 작업을 수행 할 수 있습니다.

>>> [x**2 for x in range(1,11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

여기 range(1,11)에서 list를 생성 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]하지만 range함수는 Python 3.0 이전의 생성기가 아니므로 내가 사용한 구조는 목록 이해입니다.

동일한 작업을 수행하는 생성기를 만들고 싶다면 다음과 같이 할 수 있습니다.

>>> (x**2 for x in xrange(1,11))
<generator object at 0x7f0a79273488>

그러나 Python 3에서 range생성기는 생성기이므로 사용하는 구문 (대괄호 또는 둥근 대괄호)에만 결과가 달라집니다.


4
이것은 잘못되었습니다. 외부 표현식이 생성자인지 여부는 내부 표현식이 있는지 여부와 관련이 없습니다. 당연히 목록에서 요소를 가져 오는 생성기 표현식에는 일반적으로 그다지 중요하지 않지만 할 수 있습니다.
안티몬

더 명확하게 다시 작성할 수 있습니까? 나는 당신이 말하는 것을 이해하지만 안티 모니가 말했듯이 당신이 다른 것을 말하는 것 같습니다. (그리고 당신이 말하는 것처럼 보이는 것은 잘못된 것입니다)
린든 화이트

3

Generator Comprehension은 특정 구조의 생성기를 생성하는 쉬운 방법입니다. 의 generator모든 짝수를 하나씩 출력 하는 a를 원한다고 가정 해 보겠습니다 your_list. 함수 스타일을 사용하여 만들면 다음과 같습니다.

def allEvens( L ):
    for number in L:
        if number % 2 is 0:
            yield number

evens = allEvens( yourList )

이 생성기 이해 표현식으로 동일한 결과를 얻을 수 있습니다.

evens = ( number for number in your_list if number % 2 == 0 )

두 경우 모두, 당신이 호출 할 때 next(evens)당신의 다음 짝수를 얻을 your_list.


0

생성기 이해는 리소스에서 이동하는 커서와 같은 반복 가능한 항목을 생성하는 접근 방식입니다. mysql 커서 또는 mongodb 커서를 알고 있다면 전체 실제 데이터가 한 번에 메모리에로드되지 않고 한 번에 하나씩로드된다는 것을 알 수 있습니다. 커서는 앞뒤로 이동하지만 메모리에는 항상 하나의 행 / 목록 요소가 있습니다.

요컨대, 생성기 이해력을 사용하면 파이썬에서 커서를 쉽게 만들 수 있습니다.


-1

Generator 이해의 또 다른 예 :

print 'Generator comprehensions'

def sq_num(n):
    for num in (x**2 for x in range(n)):    
        yield num

for x in sq_num(10):
    print x 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.