Python의 이터레이터와 제너레이터에 대해 알아봅니다.
a = [1, 2, 3]
next(a) # 오류
a = [1, 2, 3]
ia = iter(a)
type(ia) # <class 'list_iterator'>
next(ia) # 1
next(ia) # 2
next(ia) # 3
next(ia) # StopIteration 예외
a = [1, 2, 3]
ia = iter(a)
for i in ia:
print(i)
# 1
# 2
# 3
__iter__ 메서드: 이터레이터 객체 자신을 반환.__next__ 메서드: 다음 값을 반환하고, 더 이상 값이 없으면 StopIteration 예외를 발생.# iterator.py
class MyIterator:
def __init__(self, data):
self.data = data
self.position = 0
def __iter__(self):
return self
def __next__(self):
if self.position >= len(self.data):
raise StopIteration
result = self.data[self.position]
self.position += 1
return result
if __name__ == "__main__":
i = MyIterator([1,2,3])
for item in i:
print(item)
__init__ 메서드: 이터레이터를 초기화.__iter__ 메서드: 이터레이터 객체 자신을 반환한다return self로 자기 자신을 반환한다.__next__ 메서드: 다음 값을 반환.=> 이렇게 구현하면 next() 함수나 for 문에서 사용할 수 있는 이터레이터 완성!
# reviterator.py
class ReverseIterator:
def __init__(self, data):
self.data = data
self.position = len(self.data) -1
def __iter__(self):
return self
def __next__(self):
if self.position < 0:
raise StopIteration
result = self.data[self.position]
self.position -= 1
return result
if __name__ == "__main__":
i = ReverseIterator([1,2,3])
for item in i:
print(item)
__iter__와 __next__ 메서드를 구현해야 하는 등 복잡하다. 하지만 제너레이터를 사용하면 함수 하나만으로 간단하게 이터레이터를 만들 수 있다.def mygen():
yield 'a'
yield 'b'
yield 'c'
g = mygen()
type(g) # <class 'generator'>
next(g) # 'a'
next(g) # 'b'
next(g) # 'c'
next(g) # StopIteration 오류
# generator.py
def mygen():
for i in range(1, 1000):
result = i * i
yield result
gen = mygen()
print(next(gen)) # 1
print(next(gen)) # 4
print(next(gen)) # 9
gen = (i * i for i in range(1, 1000))
import time
def longtime_job():
print("job start")
time.sleep(1) # 1초 지연 - 실제로는 데이터베이스 조회, 파일 처리 등을 시뮬레이션
return "done"
# 리스트 컴프리헨션: 5번의 작업을 모두 실행해서 리스트로 만든다
list_job = [longtime_job() for i in range(5)]
print(list_job[0]) # 첫 번째 결과만 필요한 상황
import time
def longtime_job():
print("job start")
time.sleep(1)
return "done"
# 제너레이터 표현식: 함수를 미리 실행하지 않고 필요할 때만 실행
list_job = (longtime_job() for i in range(5))
print(next(list_job)) # 첫 번째 값만 요청