iter 함수
하나 이상의 값을 저장하는 일과 저장된 값들을 하나씩 꺼내 보는 일은 단순하지만 중요한 일이다.
ds = [1, 2, 3, 4]
for i in ds:
print(i, end = ' ' )
i
=> 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
위 예제에서는 iter라는 이름의 함수를 호출하면서 리스트를 전달했다. 그러면 iter 함수는 객체를 생성해서 반환하는데, 이는 리스트에서 값을 꺼내는 기능을 제공하는 객체이다.
즉, 위 예제에서는 다음과 같이 리스트 ds를 전달하면서 iter 함수를 호출하였다.
ir = iter(ds) # iterator 객체를 얻는 방법
그러면 iter 함수는 리스트 ds에 접근하는 도구인 iterator 객체라는 것을 생성해서 반환한다. 즉, 위의 코드가 실행되면 변수 irsms iterator 객체를 참조하는 상황이 된다. 이어서 이 객체를 전달하면서 다음과 같이 next 함수를 호출해서 리스트에 저장된 값을 하나씩 얻을 수 있다.
next(ir) # 다음 값을 반환
iterable 객체와 itrator 객체의 구분
iter 함수가 반환하는 객체를 가리켜 iterator 객체라 하고 iterator 객체를 얻을 수 있는 리스트와 같은 객체를 가리켜 iterable 객체라 한다.
Iterable 객체 : iter 함수에 인자로 전달 가능한 객체
Iterator 객체 : iter 함수가 생성해서 반환하는 객체
어떤 객체가 iterable 객체인지 확인하는 가장 쉬운 방법은 iter 함수에 전달해 보는 것이다. 전달 결과로 오류 없이 iterator 객체가 만들어진다면 이는 iterable 객체인 것이다.
iterable 객체를 대상으로 iter 함수를 호출해서 iterator 객체를 만든다.
스페셜 메서드
iter 함수와 next 함수는 객체에 속하지 않는 함수처럼 보인다.
ds = [1, 2, 3]
ir = iter(ds)
next(ir)
=> 1
next(ir)
=> 2
그러나 위 예제의 실제 함수 호출 형태는 다음과 같다.
ds = [1, 2, 3]
ir = ds.__ite.r__() # iter 함수 호출의 실제 모습
ir.__next__() # next 함수 호출의 실제 모습
=>1
ir.__next__()
=>2
즉, iter 함수 호출은 파이썬 인터프리터에 의해 __iter__ 메서드 호출로 이어지고, __next__ 함수 호출은 __next__ 메서드 호출로 이어진다.
리스트의 __iter__ 메서드 호출을 통해서 iterator 객체를 얻게 된다
iterator 객체의 __next__ 메서드 호출을 통해서 값을 하나씩 얻게 된다
for 문과 Iterable 객체
사실 for 문도 값을 하나씩 꺼내기 위해 iterable 객체를 생성해서 이것의 도움을 받는다.
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:
print(i, end=' ')
=>1 2 3
iterator 객체를 가져다 두어도 잘 동작하는 이유는 iter함수에 iterator 객체를 전달하면 전달된 iterator 객체를 그대로 되돌려 주기 때문이다.
ir1 = iter([1, 2, 3]) # 리스트의 iterator 객체를 얻음
ir2 = iter(ir1) # iterator 객체를 전달하면서 다시 iterator 객체를 얻음
ir1 is ir 2 # ir1 과 ir2가 참조하는 객체는 같은 객체이다.
=>True
id(ir1)
=>56478576
id(ir2)
=>56478576
따라서 iterable 객체와 iterator 객체 모두 for 문의 반복 대상이 될 수 있다. 즉, iterable 객체가 와야 하는 위치에는 iterator 객체가 올 수 있다.
이는 iterable 객체와 마찬가지로 iterator 객체도 iter 함수의 인자가 될 수 있고 또 그 결과로 iterator 객체가 반환되기 때문이다. 비록 iter 함수에 전달된 iterator 객체가 그대로 반환되는 것이지만 말이다.
'python' 카테고리의 다른 글
파이썬의 메모리 관리 (0) | 2022.04.06 |
---|---|
제너레이터 함수 (0) | 2022.03.06 |
리스트 컴프리헨션(2) (0) | 2022.03.02 |
map과 filter (0) | 2022.03.01 |
리스트 컴프리핸션 (0) | 2022.01.24 |