지연 처리(lazy evaluation)는 필요한 경우에만 값을 계산하는 효율적인 프로그래밍의 핵심 개념입니다. 역사적으로 파이썬의 모든 주요 내장 구조(리스트, 튜플)는 '탐욕적'이었습니다: 미리 모든 요소를 생성하고 메모리에 저장합니다. 데이터 양과 스트림 처리 문제의 증가로 인해 지연 계산에 대한 필요성이 생겼습니다.
문제: 탐욕적 계산은 필터링, 변환 긴 컬렉션 또는 파일 스트리밍과 같은 경우에서 결과를 점진적으로 얻을 수 있는 곳에서 메모리와 시간의 비효율적인 사용을 초래합니다.
해결책: 파이썬에서는 생성기, 반복자 및 표준 라이브러리 함수(map, filter, zip, enumerate)와 itertools 모듈을 포함하여 지연 계산을 위한 많은 도구가 생겼습니다. 이 도구들은 모두 준비된 컬렉션이 아니라 한 번에 하나의 값을 제공하는 '지연' 객체를 반환합니다.
코드 예:
result = map(lambda x: x * x, range(100)) # 생성기 반복기를 반환합니다. for y in result: print(y) # 값은 반복하면서 계산됩니다. import itertools inf = itertools.count(1) for i in inf: if i > 3: break print(i) # 1, 2, 3
주요 특징:
파이썬 3에서 map/filter 함수는 항상 리스트를 반환합니까?
아니요, 파이썬 3에서는 이 함수들이 리스트가 아니라 반복자를 반환합니다. 리스트를 얻으려면 결과를 list()로 감싸야 합니다.
x = map(int, ['1', '2']) # <map object> list(x) # [1, 2]
리스트로 변환하지 않고 map 결과의 길이를 얻을 수 있습니까?
아니요, 반복자는 미리 몇 개의 요소가 있는지 모르기 때문에 전부 지나야 길이를 알 수 있습니다. list()를 통해 계산해야 하며, 이는 지연성을 무효화합니다.
파이썬 3의 range 함수는 탐욕적입니까, 지연적입니까?
지연적입니다: range는 "range object"를 생성하며, 요청 시 요소를 '계산'하고 전체 시퀀스를 저장하지 않습니다.
스크립트가 거대한 CSV 파일을 처리하면서 list(open(f))를 통해 모든 행의 리스트를 만듭니다. 서버는 큰 파일로 인해 메모리 부족으로 '무너집니다.'
장점:
단점:
코드가 지연 처리를 사용하여 'for line in open(f)'를 통해 파일의 행을 반복하거나 map/filter를 통해 중간 컬렉션을 생성하지 않고 처리합니다.
장점:
단점: