해쟈스토리

iterable 객체 본문

파이썬/문법

iterable 객체

해쟈 2024. 6. 18. 19:47
728x90
반응형

반복 가능한 객체를 iterable 객체라고 한다. 내장형 반복가능한 객체로는 리스트, 문자열, 튜플 등이 있다. 하지만 이 외에도 반복이 가능하다. __iter__, __next__ 매직 메서드를 구현한 객체는 itrerable 객체이다.

iterable 객체를 반복하려고 하면 파이썬은 해당 객체의 iter() 함수를 호출한다. 이 함수가 처음으로 하는 것은 해당 객체에 __iter__ 메서드가 있는지 확인한다. 있으면 __iter__ 메서드를 실행한다.

 

다음은 일정 범위의 날짜를 하루 간격으로 반복하는 객체이다.

from datetime import timedelta

class DateRangeIterable:
	def __init__(self, start_date, end_date):
    	self.start_date = start_date
        self.end_date = end_date
        self._present_day = start_date
        
	def __iter__(self):
    	return self
        
    def __next__(self):
    	if self._present_day >= self.end_date:
        	raise StopIteration()
        today = self._present_day
        self._present_day += timedelta(days=1)
        return today
>>> from datetime import date
>>> for day in DateRangeIterable(date(2024, 6, 18), date(2024, 6, 20)):
		print(day)
    
2024-06-18
2024-06-19
2024-06-20

for 문을 만나면 iter()함수를 호출하고 이 함수는 객체의 __iter__ 매서드를 호출한다. 이 메서드는 반복가능한 객체를 return해야한다. 여기서는 self를 return 해줬다. 각 루프의 단계마다 자신의 next()호출하게 된다. 이것은 객체의 __next__ 메서드에게 위임한다. 요소를 어떻게 생산하고 하나씩 반환할 것인지 경정한다. 더이상 생산할 것이 없으면 StopIteration 예외를 발생시킨다. 

 

그러나 위와 같은 코드는 다시 for문을 실행했을 때 문제가 발생된다. DateRangeIterable(date(2024, 6, 18), date(2024, 6, 20)) 를 r 변수에 담고 for문을 돌리면 잘 출력이 된다. 그런데 for문을 한번 더 돌리면 어떨까?

r = DateRangeIterable(date(2024, 6, 18), date(2024, 6, 20))
for day in r:
    print(day)
    
for day in r:
    print(day)
2024-06-18
2024-06-19
2024-06-20

 

 

두번 출력될거 같지만, 실제로는 위와 같이 한번만 출력된다. r은 첫번째 for문에서 next로 끝까지 돌았기 때문이다. 그래서 이 객체를 다시 처음으로 초기화해야한다.. 어떻게?

클래스를 두개로 나누어서 진행한다. 하나는 인터페이스로 반복가능한 객체를 생성하고 다른 하나는 실제로 객체를 반복하는 역할을 한다. 이렇게 내부 구현을 다른 클래스에 위힘한다.

from datetime import date
from datetime import timedelta


class DateRangeIterable:
    def __init__(self, start_date, end_date):
        self.start_date = start_date
        self.end_date = end_date
        self._present_day = start_date

    def __iter__(self):
        return DateRangeIterator(self)


class DateRangeIterator:
    def __init__(self, date_range):
        self.date_range = date_range
        self._present_day = date_range.start_date

    def __next__(self):
        if self._present_day >= self.date_range.end_date:
            raise StopIteration
        today = self._present_day
        self._present_day += timedelta(days=1)
        return today


r = DateRangeIterable(date(2024, 6, 18), date(2024, 6, 20))
for day in r:
    print(day)

for day in r:
    print(day)

 

이렇게 하면 for문을 얼마든지 여러번 사용할 수 있다.

728x90
반응형

'파이썬 > 문법' 카테고리의 다른 글

데코레이터  (1) 2024.06.13