1. 이터레이터(iterator)
파이썬의 이터레이터(iterator)는 데이터가 하나씩 반환되는 객체입니다.
이터레이터를 생성할 때는 이터러블(iterable) 객체가 필요합니다.
이터러블 객체는 __iter__() 메서드를 가지고 있고, 이 메서드를 이용하여 이터레이터를 생성할 수 있습니다.
이터레이터의 __next__() 메서드를 호출하거나 내장 함수 next()에 이터레이터를 전달하면 이터레이터의 다음 항목이 반환됩니다.
이터레이터가 소진되어 더 이상 사용할 수 있는 데이터가 없으면 StopIteration 예외가 발생합니다.
iterator = iter([1, 2, 3, 4])
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
# 1
# 2
# 3
# 4
# Traceback (most recent call last):
# print(next(iterator))
# ^^^^^^^^^^^^^^
# StopIteration
이터레이터(iterator)도 이터레이터 객체를 반환하는 __iter__() 메서드가 있으므로 모든 이터레이터도 이터러블(iterable)입니다.
하지만 이터레이터로 이 작업을 시도하면, 이터레이터가 소진되며 빈 컨테이너처럼 보입니다.
iterator = iter([1, 2, 3, 4])
print(next(iterator))
iterator2 = iter(iterator)
print(next(iterator2))
print(next(iterator))
print(next(iterator2))
print(next(iterator))
# 1
# 2
# 3
# 4
# Traceback (most recent call last):
# print(next(iterator))
# ^^^^^^^^^^^^^^
# StopIteration
iterator = iter([1, 2, 3, 4])
print(next(iterator))
li_from_iter = list(iterator)
print(li_from_iter)
print(next(iterator))
# 1
# [2, 3, 4]
# Traceback (most recent call last):
# print(next(iterator))
# ^^^^^^^^^^^^^^
# StopIteration
https://docs.python.org/3/glossary.html#term-iterator
Glossary
>>>, The default Python prompt of the interactive shell. Often seen for code examples which can be executed interactively in the interpreter.,,..., Can refer to:- The default Python prompt of the i...
docs.python.org
2. 제너레이터(generator)
제너레이터는 이터레이터를 반환하는 함수입니다.
제너레이터 함수로 반환되는 이터레이터를 제너레이터 이터레이터라고 부르며 상황에 따라 그냥 제너레이터라고 부릅니다.
따라서 제너레이터는 함수를 의미하기도 하고, 반환되는 이터레이터를 의미하기도 하므로 사용에 주의합니다.
제너레이터는 일반적인 함수처럼 보이지만, return 키워드가 아닌 yield 키워드가 사용됩니다.
yield를 통해 이터레이터에서 순차적으로 반환되는 데이터를 생성합니다.
def generator(n):
i = 0
while i < n:
yield i
i += 1
iterator = generator(3)
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
# 0
# 1
# 2
# Traceback (most recent call last):
# print(next(iterator))
# ^^^^^^^^^^^^^^
# StopIteration
https://docs.python.org/3/glossary.html#term-generator
Glossary
>>>, The default Python prompt of the interactive shell. Often seen for code examples which can be executed interactively in the interpreter.,,..., Can refer to:- The default Python prompt of the i...
docs.python.org
3. 제너레이터 표현식
이터레이터를 반환하는 표현식입니다.
리스트 컴프리헨션처럼 작성하지만 대괄호[] 대신 소괄호()를 사용합니다.
iterator = (i for i in range(3))
print(iterator)
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
# <generator object <genexpr> at 0x102c9b850>
# 0
# 1
# 2
# Traceback (most recent call last):
# print(next(iterator))
# ^^^^^^^^^^^^^^
# StopIteration
4. lazy evaluation
이터레이터는 next() 함수를 통해 다음 데이터를 사용하기 전까지 미리 데이터를 생성해두지 않습니다.
다음 코드를 통해 확인해볼 수 있습니다.
def work(n):
print(f"({n}) working!")
return "done"
# iterator는 데이터가 필요한 순간에 함수가 실행(lazy evaluation)됩니다.
iterator = (work(i) for i in range(3))
for data in iterator:
print(data)
# (0) working!
# done
# (1) working!
# done
# (2) working!
# done
# list는 미리 함수가 동작하여 데이터가 모두 생성되어 있습니다.
list = [work(i) for i in range(3)]
for data in list:
print(data)
# (0) working!
# (1) working!
# (2) working!
# done
# done
# done
미리 데이터가 생성되지 않아 좋은 점은 저장공간을 효율적으로 사용할 수 있다는 것입니다.
제너레이터의 방식을 활용하는 함수 중 자주 사용하는 range()를 통해 확인해봅시다.
iterator = range(100000)
list = list(range(100000))
# 똑같이 숫자 10만 개를 가지고 있으나 이터레이터의 메모리 점유율이 훨씬 작습니다.
print(sys.getsizeof(iterator))
# 48
print(sys.getsizeof(list))
# 800056
참고로 range() 는 일반적인 이터레이터와 다르게 subscriptable하여 인덱스를 사용할 수도 있습니다.