초보 개발자

5강 lterable 객체와 lterator 객체 본문

Python/윤성우 열혈 파이썬

5강 lterable 객체와 lterator 객체

taehyeki 2021. 12. 16. 10:49

[ iter함수 ]

[1,2,3,4]라는 리스트가 있고 여기의 값을 하나씩 꺼내려면 for 루프를 사용하면 될 것이다. 하지만 연속으로 1 2 3 4가 다사용이 되는데 1 2 만 사용하고 좀더 있다가 3 4 를 사용하고 싶을 때도 있을 것이다. 그래서 값을 꺼내는 방법이 좀 더 유연하다면 우리가 할 수 있는 일의 범위는 넓어질 것이다. 

ds = [1,2,3,4]
ir = iter(ds) # iterator 객체를 얻는 방법
next(ir) # iterator 객체를 통해 값을 하나 꺼내는 방법 , 첫 번째 값 반환
1
next(ir) # 두 번째 값 반환
2
next(ir) # 세 번째 값 반환
3
next(ir) # 네 번째 값 반환
4

ir = iter(ds) # iterator 객체를 얻는 방법
next(ir) # 다음 값을 반환해라!

 

쉽게 이야기하면 리모콘에서 버튼을 눌러 변경하는 것과 같다.

iter함수를 호출함으로써 ( iter(ds) ) ir이라는 리모콘이 만들어 진다고 생각하면 된다.

이 리모콘에는 next라는 버튼이 있는데 처음에 next를 호출하면 맨 처음 요소를 호출한다. 누르면 하나씩 하나씩 호출이 된다. for 처럼 계속 나오는 것이 아니다.

 

여기서 리모콘의 역할을 하는, 버튼을 눌렀을 때 마다 값이 탁 탁 튀어나오는, 이 역할을 iterator객체라고 한다.

이 리모콘을 누가 전달해줬나? 리모콘을 제공할 수 있는 기능을 가진 저장소들을 iterable객체라고 한다.

Iterable 객체 : iter 함수에 인자로 전달 가능한 객체
Iterator 객체(리모콘) : iter 함수가 생성해서 반환하는 객체

 

iterator 객체를 생성할 수 있는 대상이 되는 것이 itarable 객체이다.

즉 iterable 객체를 대상으로 iter 함수를 호출해서 iterator객체를 만든다.

 

그림으로 정리하면 다음과 같다.

iter함수를 호출을 하면 iterator객체가 만들어 진다.(next 버튼을 가진 리모콘) 그리고 iterator객체를 통해서 리스트에 접근을 한다. ( 값을 하나씩 꺼내는 것을 접근한다고 한다. )

 

여기서 마지막 값을 얻은 이후에 next를 출력하면 StopIteration 예외가 발생한다.

 

[스페셜 메소드]

앞서 다음과 같은 방식으로 예제를 작성했기 때문에 iter함수와 next함수는 객체에 속하지 않는 함수처럼 보인다.

ds = [1,2,3]
ir = iter(ds)
next(ir)
1
next(ir)
2

그러나 위 예제의 실제 함수 호출 형태는 다음과 같다.

ds = [1,2,3]
ir = ds.__iter.__() # iter 함수 호출의 실제 모습
ir.__next__() # next 함수 호출의 실제 모습
1
ir.__next__()
2

이 전에 iter란 함수를 호출 했을 때 ' 아 ~ iter란 함수는 독립적으로 존재하고 인자에 리스트를  전달했구나' 라고 생각했다. 그러나 실제로는 그 인자(리스트 객체)안에 존재하는 ds.__iter__() 를 호출한 것이다.

그리고 next를 호출할 때에도 인자에 ir을 전달했었다. 이것도 실제로는 ir(리모콘객체)의 next메서드 호출로 이루어진 것이었다. ir__next__()

 

이 처럼 이름을 명시해서 호출하는 것이 아니라 다른 경로를 통해서 메소드 호출을 유도하는 것을 스페셜 메소드라고 한다.

즉 iter 함수 호출은 파이썬 인터프리터에 의해 __iter__메소드 호출로 이어지고,

ir = iter(ds) -> ir = ds.__iter__()

next 함수 호출은 __next__ 메소드 호출로 이어진다.

next(ir) -> ir.__next__()

따라서 다음과 같이 정리할 수 있다.

"리스트의 __iter__ 메소드 호출을 통해서 iterator 객체를 얻게 된다."

"iterator 객체의 __next__ 메소드 호출을 통해서 값을 하나씩 얻게 된다."

TMI ) 객체 생성시 자동으로 호출되는 __init__ 메소드도 스페셜 메소드이다. 그리고 이 스페셜 메소드의 이름 규칙은

앞 뒤에 __를 붙여주는 것이다.

 

 

[iterable 객체의 종류와 확인 방법]

일단 리스트, 튜플, 문자열을 통해서도 iterator 객체(리모콘)를 얻을 수 있다. 튜플,문자열도 iterable객체이기에 가능하다.

그리고 iterable객체인지 확인하는 방법도 존재한다. dir함수를 통해서 dir([1,2]) __iter__가 있다면 iterable객체인 것이다. 또한 hasattr([1,2], '__iter__') 를 통해서도 True False로 확인이 가능하다.

 

사실 for 루프도 값을 하나씩 꺼내기 위해 iterable객체를 생성해서 이 것의 도움을 받는다. 

기본적으로 loop의 반복 대상이 되려면 for i in (반복대상) literable 객체 이어야 한다.

 

for i in [1,2,3]:
    print(i, end=' ')
1 2 3

내부적으로는 다음과 같은 형태로 작동한다.

ir = iter([1,2,3]) # iterator 객체를 얻는다.
while True:
	try:
                i = next(ir) # iterator 객체를 통해서 값을 하나씩 꺼낸다.
                print(i, end=' ')
    	except StopIteration: # 더 이상 꺼낼 것이 없으면,
    		break #이 루프를 탈출한다.
1 2 3

따라서 for 루프의 반복 대상은 반드시 'iterable 객체'이어야 한다. iter 함수의 인자로 전달이 가능한 iterable 객체이어야한다. 그래서 iterable 객체인 리스트, 튜플, 문자열은 for 루프의 반복 대상이 될 수 있는 것이다.

 

 

 

그런데 다음 예에서 보듯이 for 루프에 iterable 객체가 아닌 iterator 객체를 두어도 정상작동한다.

ir = iter([1,2,3]) # ir에 저장되는 것은 iterator 객체
for i in ir: # for루프에 iterator 객체를 가져다 두었다.
	print(o, end=' ')
    
1 2 3

 

iterator는 iterable 자격도 가지고 있다. 즉 모든 iterator는 iterator이자 iterable이다.

이유는 iter()함수의 인자에 들어올 수 있는 자격은 iterable이어야 하는데 iterator도 인자가 될 수 있기 때문에 iterable자격도 주어지는 것이다.

그럼 iter에 iterator가 들어가면 리모콘의 리모콘이 만들어지느냐?? 이건 또 아니다.

iter입장에서는 리모콘을 만들어 줄려고하는데 리모콘이 들어왔네? 야 너 이미 리모콘이잖아 나가~ 하면서 그상태 그대로 쫓겨난다.

ir1 = iter([1,2,3]) #리스트의 iterator 객체를 얻음

ir2 = iter(ir1) # iterator 객체를 전달하면서 다시 iterator 객체를 얻음

ir1 is ir2 #ir1과 ir2가 참조하는 객체는 같은 객체이다.
True

id(ir1) # ir1이 참조하는 객체의 위치 정보 확인
ex) 56478576

id(ir2) # ir2가 참조하는 객체의 위치 정보 확인
ex) 56478576

 

1. 리스트를 대상으로 해서 리모콘을 만들고 ir1이 그걸 참조한다.

2. 다시 리모콘을 만들려고 했는데 이미 리모콘이라 아무일도 일어나지 않고 반환해버린다. 그걸 ir2이 참조한다.

3. 즉 ir1 과 ir2가 참조하는 리모콘은 같다. 

 

총 내용을 정리해보자면

iterable 객체와 iterator 객체 모두 for 루프에 반복 대상이 될 수 있다.

iterable 객체가 와야하는 위치에 iterator 객체가 올 수 있다.

이는 iterable 객체와 마찬가지로 iterator 객체도 iter 함수의 인자가 될 수 있고 또 그 결과로 iterator 객체가 반환되기 때문이다. 비록 iter 함수에 전달된 iterator 객체가 그대로 반환되는 것이지만 말이다.