[python] 이터레이터 (iterator), `__iter__`, `__getitem__`

gunny·2024년 3월 5일
0

Python

목록 보기
5/29

iterator (이터레이터)

  • 이터레이터(iterator)는 값을 차례대로 꺼낼 수 있는 객체(object) 이다.
    여기서 잠깐 python에서는 iterableiterator 가 있다.

[1] iterable

  • 반복 가능한 객체를 말한다.
    대표적으로 iterable한 type은 list, dictionary, set, str, bytes, tuple, range 이 있다.
    ( 그 반대로 iterable 하지 않은 type은 int, float, none)

  • 객체가 반복 가능한 객체인지 확인하는 방법은 객체에 __iter__ 메서드가 있는지 확인하는 것이다. 이 때 dir(객체) 로 확인 가능하다.

[2] iterator

  • 값을 차례대로 꺼낼 수 있는 객체를 말한다.
    iterator는 iterable한 객체를 내장함수 또는 iterable 객체의 메소드로 객체를 생성할 수 있다.
  • python 내장함수 iter()를 사용해 iterator 객체를 만들 수 있다.
a = [1,2,3]
a_iter = iter(a)
type(a_iter)

## output
<class 'list_iterator'>
  • iterator가 값을 차례로 꺼낼 수 있는 객체라고 했으므로, 배열의 이터레이터를 변수에 저장후 __next__ 메서드를 호출하면 요소를 차례대로 꺼낼 수 있다.
    a_iter에 담았던 배열의 원소인 [1,2,3]이 순서대로 출력된다.
next(a_iter)
## output 
1

next(a_iter)
## output
2

next(a_iter)
## output
3

next(a_iter)
## output
Traceback (most recent call last):
	File "<stdin>", line 1, in <module>
StopIteration 

네 번째 실행에서는 StopIteration이라는 예외가 발생한다.

  • __next__로 더 이상 꺼낼 요소가 없는 경우에는 위와 같은 예외가 발생한다.

위에서 언급한 iterable 객체는 매직메소드 __iter()__ 를 가지고 있는데, 해당 메소드로 iterator를 만들 수 있다.

b = {1,2,3}
dir(b)

## output
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']

b_iter = b.__iter__()
type(b_iter)

## output
<class 'set_iterator'>

여기서 iterator 매직 메소드의 'next'를 통해서도 하나씩 값을 꺼내 볼 수 있다.


b_iter.__next__()
## output
1

b_iter.__next__()
## output
2

b_iter.__next__()
## output
3

iterable, iterator의 차이

  • iterable은 순회 가능한 객체로, __iter__() 메소드를 구현하고, 이 메서드는 순회를 시작할 때 호출한다. 리스트, 튜플, 문자열과 같은 여러 컨테이너 타입을 말한다.

  • iterator은 반복자로, 순회 가능한 객체인 iterable에서 값을 하나씩 가져오는 객체이다.
    iterator는 __iter()__next__() 메소드를 구현해야 한다. __iter__()는 iterator 자체를 반환하고 __next__()는 다음 값을 반환한다.

  • python에서 Iterable은 Iterator로 자동 변환 되는데,
    Iterable은 iter() 함수를 통해서 Iterator로 변환할 수 있다.

  • Iterable은 모든 값을 메모리에 가지고 있어야 하지만 Iterator는 필요한 값만 생성해 메모리를 효율적으로 사용한다.

__iter__(), __getitem__

  • __iter__, __getitem__은 python에서 컬렉션 타입의 객체를 만들거나 순회할 때 사용하는 특별한 메서드이다.

[1] __iter__

  • __iter__()는 객체를 iterable(순회 가능한 객체)로 만들기 위해 서용된다.
  • 객체가 순회 가능한지 여부를 결정하고, 순회할 때 어떻게 동작할지 저으이한다.
  • 해당 메소드는 Iterator(반복자)를 반환해야 하는데, iterator는 위에서 언급한 바와 같이 __next__ 메소드를 구현하고 다음 값을 반환하거나 더 이상 값이 없으면 Stopiteration 예외를 발생시켜야 한다.

아래와 같이 사용 가능하다.


class MyIterable:
	def __init__(self, data):
    	self.data = data
    def __iter__(self):
    	return self.index = 0
        return self
    def __next__(self):
    	if self.index < len(self.data):
        	result = result.data[self.index]
            self.index +=1
            return result
        else:
        	raise StopIteration
            
my_obj = MyIterable([1,2,3,4,5])

for element in my_obj:
	print(element)
    
## output
1, 2, 3, 4, 5

[2] __getitem__

  • 객체에 인덱싱을 지원하게 만드는 메소드이다.
  • 인덱스를 받아 해당 인덱스의 값을 반환할때 사용한다.
  • 리스트, 튜플과 같이 순회 가능한 객체(iterable) 를 만들 때 주로 사용된다.

코드를 예로 들자면 다음과 같다.

class MyIndexable():
	def __init__(self):
    	self.data = [1,2,3,4,5]
        
    def __getitem__(selft, index):
    	return self.data[index]
  
obj = MyIndexable([1,2,3,4,5])
print(obj[2]

## output
3

참고사이트

[1] https://wikidocs.net/16068
[2] https://skyfox83.tistory.com/120

profile
꿈꾸는 것도 개발처럼 깊게

0개의 댓글