Iterable : 여러개의 데이터를 하나씩 또는 한 단위씩 제공하는 객체, 값을 가지고 있다.
- 특수메소드 __iter__()를 정의
Iterator : 값을 가지고 있지는 않지만 Iterable이 가지고 있는 값을 하나씩 또는 한 단위씩 제공하는 객체.
- 특수메소드 __next__()를 정의
l = [1, 2, 3] # 리스트 -> list -> iterable -> __iter__() 구현
l_iterator = iter(l) # iter(iterable객체) -> iterable객체.__iter__()
# l_iterator = l.__iter__()
print(type(l), type(l_iterator))
t = (1, 2, 3, 4)
t_iterator = iter(t)
print(type(t_iterator))
# iterator의 __next__() 메소드를 호출 -> next(iterator)
# 자기를 생성한 iterable객체의 원소를 하나 반환
print(next(l_iterator)) # 반복실행하다가 더 이상 제공할 값이 없을 경우 -> StopIteration
iterable = [1, 2, 3, 4, 5]
# 1. iterable -> iterator 생성
iterator = iter(iterable)
while True:
try: # try except로 StopIteration에 대한 처리를 정한다.
value = next(iterator)
print(value)
except StopIteration: # StopIteration -> 내장함수
break
print('다음작업')
forIn문 활용
def forIn(iterable, func):
# iterable : 원소를 제공할 iterable 객체
# func : 각 원소를 처리한 함수.
iterator = iter(iterable)
while True:
try:
value = next(iterator)
func(value)
except StopIteration:
break
forIn([1, 2, 3], lambda x : print(x))
forIn((10, 20, 30), lambda x : print(x))
# Iterable 과 Iterator를 구현
# 각각 다른 클래스로 구현
class MyIterable:
def __init__(self, *args):
# **args : 제공할 원소값들을 가변인자로 받기.
self.values = args
# iterable
def __iter__(self):
# Iterable은 반드시 __iter__() 특수함수를 구현해야 한다.
# __iter__()는 Iterator객체를 반환하도록 구현.
return MyIterator(self.values)
# subscriptable - indexing 가능
def __getitem__(self, index):
return self.values[index]
# len(객체) 호출되는 특수메소드 -> 원소의 개수를 반환
def __len__(self):
return len(self.values)
i = MyIterable(1, 2, 3)
print(i[2]) # __getitem__() 함수가 있어야 실행된다.
print(len(i)) # __len__() 함수가 있어야 실행된다.
class MyIterator:
def __init__(self, values):
# Iterator가 제공할 값을 MyIterable로부터 받는다.
self.values = values
self.index = 0 # 제공할 값의 index
def __next__(self):
# Iterator는 반드시 __next__() 특수 메소드를 구현해야 한다.
# Iterable에서 받은 원소들에서 하나의 값을 순서대로 제공하도록 구현.
# 더 제공할 값이 없으면 StopIteration 예외를 발생
if len(self.values) <= self.index:
raise StopIteration()
r_value = self.values[self.index] # 제공할 값을 조회
self.index += 1 # index를 하나 증가
return r_value
i = MyIterable(1, 2, 3, 4, 5) # iterable 생성
it = iter(i) # iterable로부터 iterator 생성
# iterator로부터 한개의 값을 조회
next(it) # 반복실행시 다음 인덱스의 값이 출력된다. index값을 초과하면 StopIteration 발생
it.index # 현재 인덱스 출력
i = MyIterable(1, 2, 3, 4, 5) # iterable 생성
# for v in i:
for v in MyIterable(1, 2, 3, 4, 5): # for v in i 대신 바로 iterable을 생성하면서 for in 문 가능
print(v) # StopIteration이 발생하지 않는다.
i[0] # -> Iterable에 def __getitem__(self, idx): idx번째 값을 반환하는 메소드
Generator : Iterable과 Iterator를 합친 기능을 함수 형태로 구현
return 대신 yield를 사용한다. yield가 들어가면 Generator
구문 : yield 반환값 -> 반환값을 가지고 호출한 곳으로 돌아가지만 return과 다르게 돌아가기 직전의 상태를 기억하면서 돌아간다.
- yield 를 다시 실행하면 이전 yield구문 다음부터 실행한다.
Generator의 원소 조회 : next(Generator 객체)
def my_gen():
yield 10
yield 2
yield 3
g = my_gen() # generator 객체를 생성
# generator 호출
next(g) # yield다음구문 -> yield
next(g) # 반복실행하며 결과 확인하기
# 파라미터로 받은 값에서 5씩 증가하는 값을 3번 제공
def my_gen2(start):
start += 5
yield start
start += 5
yield start
start += 5
yield start
g2 = my_gen2(10)
print(next(g2))
print(next(g2)) # 반복실행하며 결과확인하기
def my_gen3(start, n):
# start부터 5씩 증가하는 값을 n개 제공
for _ in range(n):
start += 5
yield start
g3 = my_gen3(1, 10) # generator 객체 생성
next(g3) # 반복실행시 5씩 늘어난다.
v = next(g3)
print(v)
v = next(g3)
print(v) # 결과 확인하기
컴프리헨션 : 리스트, 딕셔너리, 셋, 제너레이터 -> 튜플 컴프리헨션이 없고 ()는 제너레이터 컴프리헨션이다.
Generator 컴프리헨션 표현식 : 컴프리헨션 구문을 ()로 묶어 표현
- 로직만을 기억하고 있기에 메모리 효율이 다른 컴프리헨션들보다 좋다.
g4 = (value+5 for value in range(10)) # generator 만들기 컴프리헨션 문법을 이용함
next(g4) # 반복실행하면서 결과확인
!!간단한 값을 가져오려면 컴프리헨션이 편하지만 다양하고 복잡한 조건등을 구현하려면 Iterable과 Iterator를 사용한다.
'Data_Analysis_Track_33 > Python' 카테고리의 다른 글
| Python_10(파이썬 정규 표현식) (0) | 2023.08.28 |
|---|---|
| Python_09-2(Decorator) (0) | 2023.08.28 |
| Python_08-2(입출력) (0) | 2023.08.25 |
| Python_08(입출력) (0) | 2023.08.24 |
| Python_07-2(Exception 발생시키기) (0) | 2023.08.24 |