for (반복자) in (반복할 수 있는 것)
반복할 수 있는 것을 이터러블(Iterable)이라 함.이터러블(Iterable)은 내부에 있는 요소들을 하나씩 꺼낼 수 있는 객체를 의미함.Ex.리스트, 딕셔너리, 문자열, 튜플 등 모두 내부에서 요소를 하나씩 꺼낼 수 있으므로 이터러블(Iterable)임.이터러블(Iterable)중에서 next()함수를 이용해 하나씩 꺼낼 수 있는 요소를 이터레이터(Iterator)라 함.이터러블(Iterable)은 내부 요소들을 하나씩 꺼낼 수 있는 이터레이터를 생성할 수 있는 객체.즉, 이터러블(Iterable)은 반복문에서 사용할 수 있는 객체로서 내부 요소들을 하나씩 반환하는 이터레이터를 생성할 수 있는 객체를 의미함.
이터레이터(Iterator)는 next() 함수를 이용해 요소를 하나씩 반환하는 객체이며
더 이상 반환할 값이 없을 경우 StopIteration 예외를 발생시킴.
for문은 내부적으로 이터러블에서 이터레이터를 생성하고
반복할 때마다 next()를 호출하여 요소를 하나씩 꺼냄.
list_a = [1, 2, 3, 4, 5]
list_a_reversed = reversed(list_a)
print("reversed() 사용.")
print("reversed(list_a) : ", list_a_reversed)
print("list(reversed(list_a)) : ", list(list_a_reversed))
print()
print("reversed()와 반복문")
print("for i in reversed(list_a):")
for i in reversed(list_a):
print("-", i)
-- 실행 결과 --
reversed() 사용.
reversed(list_a) : <list_reverseiterator object at 0x000001C7C125B9D0>
list(reversed(list_a)) : [5, 4, 3, 2, 1]
reversed()와 반복문
for i in reversed(list_a):
- 5
- 4
- 3
- 2
- 1
reversed()함수를 사용.reversed()는 이터레이터(Iterator)를 반환함.Why? 왜 reversed() 함수는 리스트를 바로 반환하는 게 아니라 이터레이터를 반환할까?메모리의 효율성을 위해서.지연 평가(lazy evaluation)필요할 때만 값을 하나씩 생성하기 때문에 메모리를 거의 쓰지 않음.nums = range(1_000_000_000)
rev = reversed(nums)
이터러블 전체를 반환했다면 모든 원소를 복사해서 새 리스트를 만들었기 때문에 비효율적임.numbers = [1, 2, 3, 4, 5, 6]
reversed_num = reversed(numbers)
print("reversed_num : ", reversed_num)
print("첫 번째 : ", next(reversed_num))
print("두 번째 : ", next(reversed_num))
print("세 번째 : ", next(reversed_num))
print("네 번째 : ", next(reversed_num))
print("다섯 번째 : ", next(reversed_num))
print("여섯 번째 : ", next(reversed_num))
-- 실행 결과 --
reversed_num : <list_reverseiterator object at 0x000001A960ABBA60>
첫 번째 : 6
두 번째 : 5
세 번째 : 4
네 번째 : 3
다섯 번째 : 2
여섯 번째 : 1
reversed()의 반환값이 이터레이터인 것을 확인.next()를 통해 이터레이터의 값을 하나씩 꺼내서 출력.numbers = [1, 2, 3, 4, 5, 6]
reversed_num = reversed(numbers)
print("reversed_num : ", reversed_num)
print("첫 번째 : ", next(reversed_num))
print("두 번째 : ", next(reversed_num))
print("세 번째 : ", next(reversed_num))
print("네 번째 : ", next(reversed_num))
print("다섯 번째 : ", next(reversed_num))
print("여섯 번째 : ", next(reversed_num))
print()
for i in reversed_num:
print(f'i = {i}')
-- 실행 결과 --
reversed_num : <list_reverseiterator object at 0x000001ADB318BA60>
첫 번째 : 6
두 번째 : 5
세 번째 : 4
네 번째 : 3
다섯 번째 : 2
여섯 번째 : 1
----
numbers = [1, 2, 3, 4, 5, 6]
reversed_num = reversed(numbers)
print("reversed_num : ", reversed_num)
print("첫 번째 : ", next(reversed_num))
print("두 번째 : ", next(reversed_num))
print("세 번째 : ", next(reversed_num))
print("네 번째 : ", next(reversed_num))
print("다섯 번째 : ", next(reversed_num))
print("여섯 번째 : ", next(reversed_num))
print('----')
reversed_num = reversed(numbers) # 새로 생성.
for i in reversed_num:
print(f'i = {i}')
-- 실행 결과 --
reversed_num : <list_reverseiterator object at 0x000001A974A0BA60>
첫 번째 : 6
두 번째 : 5
세 번째 : 4
네 번째 : 3
다섯 번째 : 2
여섯 번째 : 1
----
i = 6
i = 5
i = 4
i = 3
i = 2
i = 1
list_a = [1, 2, 3]
next(list_a)
-- 실행 결과 --
Traceback (most recent call last):
File "c:\Python-study\08\tmp.py", line 2, in <module>
next(list_a)
TypeError: 'list' object is not an iterator
리스트는 이터레이터 객체가 아니다라는 에러가 발생했음.But 반복 가능하다면 아래와 같이 iter()함수를 이용해서 이터레이터로 만들 수 있음.list_a = [1, 2, 3]
iterator_a = iter(list_a)
print(type(iterator_a))
-- 실행 결과 --
<class 'list_iterator'>
list_a = [1, 2, 3]
iterator_a = iter(list_a)
print(next(iterator_a))
print(next(iterator_a))
print(next(iterator_a))
print(next(iterator_a))
-- 실행 결과 --
1
2
3
Traceback (most recent call last):
File "c:\Python-study\08\tmp.py", line 9, in <module>
print(next(iterator_a))
^^^^^^^^^^^^^^^^
StopIteration
class MyItertor:
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
i = MyItertor([1,2,3])
for item in i:
print(item)
-- 실행 결과 --
1
2
3
__iter__와 __next__ 이렇게 총 두 개의 메서드를 구현하면 만들 수 있음.__iter__ 메서드와 __next__ 메서드를 구현하였음.__iter__ 메서드는 이터레이터 객체를 반환하는 메서드이므로 MyIterator 클래스에 의해 생성되는 객체를 의미하는 self를 반환.__next__ 메서드는 next() 함수 호출 시 수행되므로 MyIterator 객체 생성 시 전달한 데이터를 하나씩 반환하도록 하고 더 이상 반환할 값이 없으면 StopIteration 예외를 발생.class ReverseItertor:
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
i = ReverseItertor([1,2,3])
for item in i:
print(item)
-- 실행 결과 --
3
2
1
리스트(list): 모든 데이터를 즉시 메모리에 저장함.제너레이터(generator): 요청이 있을 때마다 하나씩 생성함.yield 키워드를 사용하면 해당 함수는 제너레이터 함수가 되고 일반 함수와 다르게 함수를 호출해도 함수 내부의 코드가 실행되지 않음.next()함수를 사용해서 함수 내부의 코드를 실행함.yield까지만 실행하고 next() 함수의 리턴값으로 yield 뒤에 입력되어 있는 값이 출력됨.일회용임.def generator_test():
print("함수 호출")
yield "test"
print("A 통과")
generator_test()
print("B 통과")
generator_test()
print(generator_test()) # 제너레이터 함수는 제너레이터를 리턴함.
-- 실행 결과 --
A 통과
B 통과
<generator object generator_test at 0x000001FC1E0C4B80>
def generator_test():
print("A 통과")
yield "A"
print("B 통과")
yield "B"
print("C 통과")
# yield "C" 없음.
result = generator_test()
print("D 통과")
print(next(result))
print('----------')
print("E 통과")
print(next(result))
print('----------')
print("F 통과")
print(next(result))
print('----------')
-- 실행 결과 --
D 통과
A 통과
A
----------
E 통과
B 통과
B
----------
F 통과
C 통과
Traceback (most recent call last):
File "c:\Python-study\05\generator_next.py", line 18, in <module>
print(next(result))
^^^^^^^^^^^^
StopIteration
StopIteration예외가 발생함.def generator_ex():
yield '1'
yield '2'
yield '3'
generator_var = generator_ex()
print(type(generator_var))
print(next(generator_var))
print(next(generator_var))
print(next(generator_var))
print(next(generator_var))
-- 실행 결과 --
<class 'generator'>
1
2
3
Traceback (most recent call last):
File "c:\Python-study\05\generator_ex.py", line 11, in <module>
print(next(generator_var))
^^^^^^^^^^^^^^^^^^^
StopIteration
def gen():
yield 10
yield 20
yield 30
g = gen()
for x in g:
print(x)
print("다시 반복")
for x in g:
print(x)
- 출력 결과 -
10
20
30
다시 반복
def gen():
yield 10
yield 20
yield 30
lst = [10, 20, 30] # 리스트
g = (x for x in lst) # 제너레이터
print('리스트1: ', list(lst))
print('리스트2: ', list(lst))
print('제너레이터1: ', list(g))
print('제너레이터2: ', list(g))
- 출력 결과 -
리스트1: [10, 20, 30]
리스트2: [10, 20, 30]
제너레이터1: [10, 20, 30]
제너레이터2: []