[python] 생성기 표현 대 목록 이해

언제 파이썬에서 생성자 표현식을 사용해야하고리스트 이해를 사용해야합니까?

# Generator expression
(x*2 for x in range(256))

# List comprehension
[x*2 for x in range(256)]



답변

John의 대답 은 좋습니다 (여러 번 반복해서 반복하려고 할 때 목록 이해력이 더 좋습니다). 그러나 목록 방법 중 하나를 사용하려면 목록을 사용해야한다는 점도 주목할 가치가 있습니다. 예를 들어 다음 코드는 작동하지 않습니다.

def gen():
    return (something for something in get_some_stuff())

print gen()[:2]     # generators don't support indexing or slicing
print [5,6] + gen() # generators can't be added to lists

기본적으로 생성자가 한 번만 반복하면 생성기 표현식을 사용하십시오. 생성 된 결과를 저장하고 사용하려면 목록을 이해하는 것이 좋습니다.

성능이 다른 것을 선택하는 가장 일반적인 이유이므로, 내 조언은 걱정하지 않고 하나만 선택하는 것입니다. 프로그램이 너무 느리게 실행되고있는 경우에만 돌아가서 코드 튜닝에 대해 걱정해야합니다.


답변

생성기 표현식 또는 목록 이해 를 반복 하면 동일한 작업이 수행됩니다. 그러나 목록 이해 는 메모리에 전체 목록을 먼저 생성 하고 생성기 표현식 은 즉시 항목을 생성하므로 매우 큰 (및 무한대) 시퀀스에 사용할 수 있습니다.


답변

결과를 여러 번 반복해야하거나 속도가 가장 중요한 경우 목록 이해를 사용하십시오. 범위가 크거나 무한한 생성기 표현식을 사용하십시오.

자세한 내용은 생성기 표현식 및 목록 이해 를 참조하십시오.


답변

중요한 점은 목록 이해가 새로운 목록을 생성한다는 것입니다. 생성기는 비트를 소비 할 때 소스 자료를 “필터링”하는 반복 가능한 객체를 생성합니다.

“hugefile.txt”라는 2TB 로그 파일이 있고 “ENTRY”라는 단어로 시작하는 모든 행의 내용과 길이를 원한다고 가정하십시오.

따라서 목록 이해력을 작성하여 시작해보십시오.

logfile = open("hugefile.txt","r")
entry_lines = [(line,len(line)) for line in logfile if line.startswith("ENTRY")]

이렇게하면 전체 파일을 정리하고 각 줄을 처리하며 일치하는 줄을 배열에 저장합니다. 따라서이 어레이에는 최대 2TB의 컨텐츠가 포함될 수 있습니다. 그것은 많은 RAM이며 아마도 귀하의 목적에 실용적이지 않을 것입니다.

대신 생성기를 사용하여 콘텐츠에 “필터”를 적용 할 수 있습니다. 결과를 반복하기 시작할 때까지 실제로 데이터를 읽지 않습니다.

logfile = open("hugefile.txt","r")
entry_lines = ((line,len(line)) for line in logfile if line.startswith("ENTRY"))

아직 파일에서 한 줄도 읽지 않았습니다. 실제로 결과를 더 필터링하고 싶다고 가정 해보십시오.

long_entries = ((line,length) for (line,length) in entry_lines if length > 80)

아직 읽은 것은 없지만 지금 우리가 원하는대로 데이터에 작용할 두 개의 생성기를 지정했습니다.

필터링 된 줄을 다른 파일에 쓸 수 있습니다.

outfile = open("filtered.txt","a")
for entry,length in long_entries:
    outfile.write(entry)

이제 입력 파일을 읽습니다. for루프가 계속해서 추가 라인을 요청 함에 따라 long_entries생성기 는 생성기에서 라인을 요구 entry_lines하며 길이가 80자를 초과하는 라인 만 반환합니다. 그리고 entry_lines생성기는 logfile반복자에게 행을 요청하고 (표시된대로 필터링 됨) 파일을 읽습니다.

따라서 완전히 채워진 목록의 형태로 출력 함수에 데이터를 “푸시”하는 대신 출력 함수에 필요할 때만 데이터를 “풀”하는 방법을 제공합니다. 이것은 우리의 경우 훨씬 더 효율적이지만 융통성이 없습니다. 제너레이터는 일방 통행입니다. 읽은 로그 파일의 데이터는 즉시 버려 지므로 이전 줄로 돌아갈 수 없습니다. 반면에 데이터가 완료된 후에는 데이터를 보관하는 것에 대해 걱정할 필요가 없습니다.


답변

생성기 표현식의 이점은 전체 목록을 한 번에 작성하지 않기 때문에 메모리를 덜 사용한다는 것입니다. 생성기 표현식은 결과를 합산하거나 결과에서 dict를 작성하는 등 목록이 중간 인 경우에 가장 적합합니다.

예를 들면 다음과 같습니다.

sum(x*2 for x in xrange(256))

dict( (k, some_func(k)) for k in some_list_of_keys )

이점은 목록이 완전히 생성되지 않아서 메모리가 거의 사용되지 않고 더 빠를 수 있다는 것입니다

그러나 원하는 최종 제품이 목록 인 경우 목록 이해를 사용해야합니다. 생성 된 목록을 원하므로 생성기 표현식을 사용하여 기억을 저장하지 않습니다. 정렬 또는 역순과 같은 목록 기능을 사용할 수 있다는 이점도 있습니다.

예를 들면 다음과 같습니다.

reversed( [x*2 for x in xrange(256)] )


답변

목록과 같은 가변 객체에서 생성기를 생성 할 때 생성기를 생성 할 때가 아니라 생성기를 사용할 때 목록의 상태에서 생성기가 평가된다는 점에 유의하십시오.

>>> mylist = ["a", "b", "c"]
>>> gen = (elem + "1" for elem in mylist)
>>> mylist.clear()
>>> for x in gen: print (x)
# nothing

목록이 수정 될 가능성이 있거나 생성기 생성시 상태가 필요한 경우 대신 목록 이해를 사용해야합니다.


답변

때로는 itertools 에서 tee 함수를 사용하여 벗어날 수 있으며 독립적으로 사용할 수있는 동일한 생성기에 대해 여러 개의 반복자를 반환합니다.