<이터레이터(Iterator)>
📍파이썬에서 반복 가능한 객체(클래스)를 표현하는 데 사용되는 인터페이스
📍이터레이터는 init() 함수와 next() 함수를 이용하여 반복(Iterator)을 수행함
📍__iter__() 메서드
iter 메서드는 이터레이터 객체 자체를 반환한다. 이터레이터 객체는 __iter__() 메서드를 가지고 있어야 한다. 이는 파이썬에서 "순회 가능한(iterable)" 객체의 특징이다.
📍__next__() 메서드
next 메서드는 다음 요소를 반환한다. 만약 더 이상 반환할 요소가 없으면 StopIteration 예외를 발생시켜 순회를 종료시킨다. 이 메서드가 호출될 때마다, 다음 요소를 반환하고 내부 상태를 업데이트하여 다음 호출 시에 이전 요소의 다음 요소를 반환할 수 있도록 한다.
반복문 사용하여 이터레이터 사용하기
### 클래스 정의하기
- 아래 코드는 MyIterator 클래스를 정의하고 객체를 생성한 후, for 루프를 사용하여 이터레이터를 순회하고 있다. 이터레이터 객체를 생성하면 __init__ 메서드가 호출되고, 그 후에 __iter__ 메서드가 호출되어 이터레이터 객체를 반환한다. 그리고 for 루프에서 각 단계마다 __next__ 메서드가 호출되어 반복이 수행된다. 반복이 끝나면 StopIteration 예외가 발생하여 순회가 종료된다
### 클래스 정의하기
class MyIterator :
### 클래스 생성자 정의하기
def __init__(self) :
self.current_value = 0
print(f"#1 (__init__) : self={self} / self.current_value={self.current_value}")
### 자신의 클래스를 반환하는 iter 함수 정의
def __iter__(self) :
print(f"#2 (__iter__) : self={self}")
return self
### 반복을 수행하는 next 함수 정의
def __next__(self) :
print(f"#3 (__next__) : self={self}")
### current_valu의 값이 5보다 작을 때까지 반복 수행
if self.current_value < 5 :
# - 반환할 변수에 current_value의 현재값 저장
result = self.current_value
# - result 값 반환
self.current_value += 1
print(f"#4 : result={result} / self.current_value={self.current_value}")
# - return 값 반환
return result
else :
print("#5 : StopIteration 예외 발생")
### 이터레이터는 반복이 끝나면 종료시켜야함
# - 종료시키는 방법은 강제로 오류 발생시킴
raise StopIteration
### 이터레이터 실행시키기
- 클래스 생성하기
my_iterator = MyIterator()
#1 (__init__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510> / self.current_value=0
### 반복문 실행시키기
- 이터레이터 기능은 반복문(for or while)을 사용해야만 작동하는 기능임
- 최초 __iter__() 함수를 호출하고, 출력 시 __next__() 함수가 한 번씩 수행하면서 값을 반환받아서 출력함
- 한번 반환된 후 메모리는 초기화되며, 다음 반복 시 다시 메모리 사용
- 메모리를 효율적으로 활용할 수 있음
- 반복 수행하여 result 값 출력하기
for value in my_iterator :
print(value)
#2 (__iter__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#4 : result=0 / self.current_value=1
0
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#4 : result=1 / self.current_value=2
1
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#4 : result=2 / self.current_value=3
2
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#4 : result=3 / self.current_value=4
3
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#4 : result=4 / self.current_value=5
4
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF4FF4510>
#5 : StopIteration 예외 발생
반복문 사용하지 않고 이터레이터 실행시키기
### 이터레이터 실행시키기
- 클래스 생성하기
my_iterator = MyIterator()
#1 (__init__) : self=<__main__.MyIterator object at 0x0000014EF601D110> / self.current_value=0
### 반복문 사용하지 않고 실행시키기
print(next(my_iterator))
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF5348E50>
#4 : result=0 / self.current_value=1
0
### try / except로 예외처리
try :
print(next(my_iterator))
print(next(my_iterator))
print(next(my_iterator))
print(next(my_iterator))
except :
print("이터레이터 종료")
- 처음 실행 했을 때 결과
3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF6549D10>
#4 : result=1 / self.current_value=2
1
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF6549D10>
#4 : result=2 / self.current_value=3
2
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF6549D10>
#4 : result=3 / self.current_value=4
3
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF6549D10>
#4 : result=4 / self.current_value=5
4
- 두 번 실행했을 때 결과
#3 (__next__) : self=<__main__.MyIterator object at 0x0000014EF601D110>
#5 : StopIteration 예외 발생 이터레이터 종료
간단 실습
### 이터레이터 클래스 생성해서 Hello 각 단어 출력하기
- 클래스 이름 : StringIterator
- 임의 문자열을 받아서 처리한다.
- 임의 문자열은 외부에서 클래스 생성 시 넣어준다.
내가 만든 코드
class StringIterator:
def __init__(self, word):
self.word = word
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.word):
result = self.word[self.index]
self.index += 1
return result
else:
raise StopIteration
- 코드실행
string_iter = StringIterator("안녕하세요")
for v in string_iter:
print(v)
안
녕
하
세
요
강사님 코드
- p_text 지역변수, 매개변수로써의 의미
- self.text 는 멤버 변수
- 둘이 저장되는 위치가 다름
class StringIterator_:
### 클래스 생성자
def __init__(self, p_text) :
# - next 함수에서 1씩 증가시키면서 반복 조건에 사용할 변수
self.index = 0
# - 받아온 문자열
self.text = p_text
### 반복수행을 위한 iter 함수 정의
def __iter__(self):
return self
### 한건 한건 처리를 위한 next 함수 정의
def __next__(self) :
if self.index < len(self.text) :
### 문자열에서 문자 하나씩 추출하기
result = self.text[self.index]
self.index += 1
return result
else:
raise StopIteration
- 코드 실행
### 이터레이터 기능 사용하기
# 반복문을 이용해서 추출하기
# - 클래스 생성하기
msg = "Hello"
string_iter_ = StringIterator_(msg)
- 반복문을 이용해서 전체 추출하기
for char in string_iter_ :
print(char)
H
e
l
l
o
- 따로따로 실행하기
print(next(string_iter_))
print(next(string_iter_))
print(next(string_iter_))
print(next(string_iter_))
print(next(string_iter_))
H
e
l
l
o
※ 예외처리를 안 했기 때문에 한번 더 실행하면 오류 발생
일반 프로그래밍 방식과 이터레이터 방식의 메모리 비교
### 메모리 확인을 위해 라이브러리 설치 필요
pip install memory-profiler
### 주피터 노트북 ver
## 라이브러리 불러오기
from memory_profiler import profile
### 주피터노트북에서는 아래 로드 처리 해야힘
%load_ext memory_profiler
## 이터레이터 클래스 생성하기
class SimpleIterator :
def __init__(self, limit) :
### 반복 범위를 지정할 값(반복의 끝값)
self.limit = limit
### 반복 시작값
self.current = 0
def __iter__(self) :
return self
def __next__(self) :
if self.current < self.limit :
self.current += 1
return self.current
else :
raise StopIteration
## 데코레이터 함수 정의하기
### 이터레이터를 사용하지 않고 메모리 체크하기
@profile
def no_iterator(limit) :
data = [i for i in range(1, limit+1)]
### 이터레이터를 사용해서 메모리 체크하기
@profile
def yes_iterator(limit) :
data = SimpleIterator(limit)
for item in data :
### 반복만 처리하고 별도 출력은 안함
pass
## 데코레이터 함수 호출하기
limit = 1000000
try:
%memit no_iterator(limit)
%memit yes_iterator(limit)
except:
pass
ERROR: Could not find file C:\Users\user\AppData\Local\Temp\ipykernel_3736\513312623.py
peak memory: 130.37 MiB, increment: 25.96 MiB
ERROR: Could not find file C:\Users\user\AppData\Local\Temp\ipykernel_3736\513312623.py
peak memory: 104.40 MiB, increment: 0.00 MiB
### 파이썬 ver
새로운 파일에 기존 주피터 노트북에 적은 코드에서 로드해오는 %load_ext memory_profiler 코드 빼고 작성하기
py 형태로 파일 저장한 뒤 프롬프트에서 실행하기
## 데코레이터 함수 호출하는 코드 수정
if __name__ == "__main__" :
### 데코레이터 함수 호출하기
limit = 1000000
print("no_iterator ------------------------\n")
no_iterator(limit)
print("yes_iterator ------------------------\n")
yes_iterator(limit)
## 프롬프트에서 실행시 명령어
python -m memory_profiler 04_iterator_memory_test.py
간단실습
### 두개의 숫자(시작값, 종료값) 값을 이용해서, 짝수값만 반환하는 이터레이터 만들기
내가 만든 코드
class EvenNumberIterator :
def __init__(self, start, end) :
self.start = start
self.end = end
def __iter__(self) :
return self
def __next__(self) :
if self.start <= self.end and self.start % 2 == 0 :
self.start % 2 == 0
result = self.start
self.start += 2
return result
else :
self.start += 1
raise StopIteration
- 코드 실행
num_iterator = EvenNumberIterator(1, 20)
for v in num_iterator :
print(v)
2
4
6
8
10
12
14
16
18
20
강사님 코드
class EvenNumberIterator :
def __init__(self, start, end) :
self.start = start
self.end = end
def __iter__(self) :
return self
def __next__(self) :
# - 사용하는 값은 self.start 값만 사용
for i in range(self.start, self.end, 1) :
### self.start가 짝수인지 체크
if self.start % 2 == 0:
### 반환할 변수에 저장
result = self.start
# - self.start값은 1 증가
self.start += 1
# - 반환하기 : 반환하면 for문은 종료됨
return result
### 짝수가 아니면
else :
# - 1증가만 시키고 반복을 계속 수행
self.start += 1
### for문을 이용한 경우에는, 이터레이터 반복 종류 후 마지막에 아래 추가
raise StopIteration
- 코드 실행
even_iter = EvenNumberIterator(1, 10)
for even in even_iter :
print(even)
2
4
6
8
외부 함수를 이용해서 짝수값 추출하는 이터레이터 만들기
1. 이터레이터 클래스 생성하기
class EvenNumberIterator :
### 클래스 생성자 정의
def __init__(self, start, end, func):
# - 시작값
self.start = start
# - 종료값
self.end = end
# - 외부함수
self.func = func
### 반복을 위한 이터레이터 함수 정의
def __iter__(self):
return self
### 반복 결과값을 처리할 함수 정의
def __next__(self):
### 시작부터 종료까지 while 반복
while self.start <= self.end :
### 외부함수로 짝수 or 홀수 체크
# - 짝수면 True, 홀수면 False
if self.func(self.start) :
result = self.start
self.start += 1
return result
else :
self.start += 1
### 이터레이터 종료하기
raise StopIteration
2. 짝수와 홀수를 판별하는 외부함수 정의하기
def is_even(num) :
return num % 2 == 0
3. 이터레이터 클래스 생성하기
- 함수 이름을 그대로 변수로 넣으면 함수 자체를 실행
even_iter = EvenNumberIterator(1, 10, is_even)
### 이터레이터 반복 수행하기
for v in even_iter :
print(v)
텍스트 파일의 내용을 한줄씩 반환하는 이터레이터 만들기
1. 이터레이터 클래스 생성하기
- 파일명은 클래스가 받아서 처리
- readline() : 파일 정보중에 줄 하나 가지고 오는 함수
>> 최초 이후부터는 다음 줄이 있는지 자동으로 체크 후 가지고 온다
>> 다음 줄이 없으면 안가지고 온다.
class FileLineIterator :
def __init__(self, file_path) :
# 파일 경로를 인스턴스 변수에 저장
self.file_path = file_path
# 파일 열기
self.file = open(file_path, "r", encoding = "utf-8")
def __iter__(self):
return self
def __next__(self):
print("#1 ---------------------")
# 파일에서 한 줄 읽어오기
line = self.file.readline()
# 읽어온 줄이 있으면 반환하고, 없으면 종료
if line:
# strip은 문자열의 양 끝에서 공백 문자(공백, 탭, 개행문자 등)을 제거하는 역할
return line.strip()
else :
# 파일 닫기와 StopIteration 예외 발생
print("#4 : 이터레이터 종료")
self.file.close()
raise StopIteration
2. 이터레이터 클래스 생성하기
file_path = "./04_example.txt"
file_iter = FileLineIterator(file_path)
3. 반복해서 파일 내용 한줄씩 출력하기
for line in file_iter :
print(line)
- 메모장 내용과 주피터 노트북 실행 결과
# 결과
#1 ---------------------
가가가
#1 ---------------------
나나나
#1 ---------------------
다다다
#1 ---------------------
라라라
#1 ---------------------
#4 : 이터레이터 종료
'Digital Boot > Python' 카테고리의 다른 글
[Python] 파이썬 정규표현식(Regular_Expression) (0) | 2023.11.16 |
---|---|
[Python] 파이썬 제너레이터(Generator) (0) | 2023.11.16 |
[Python] 파이썬 데코레이터(Decorator) (2) | 2023.11.14 |
[Python] 파이썬 매개변수 (1) | 2023.11.14 |
[Python] 파이썬 도서 관리 프로그램 만들기 실습 2 (0) | 2023.11.14 |