본문 바로가기

Data_Analysis_Track_33/Python

Python_09(Iterable)

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