Iterable and Iterator, and Generator

Iterable
for문에서in뒤에 위치하여 iterate (반복, 순회)가 가능한 object를 가르킴.__iter__()라는 special method를 구현하고 있으며, 이를 통해 자신에 대한iteratorobject를 반환할 수 있음.__iter__()special method는- 보통
iter()함수에 argument로 "iterableinstance"가 전달되는 경우 - 해당 argument로 넘겨진 객체(=iterable 객체)의
__iter__()메서드 가 호출되어 - 반환되는
iterator객체가iter()함수에서 최종 반환됨.
- 보통
- 여러 데이터를 묶어서 관리하는
Collection들의 object들의 경우, 거의 다iterableobject라고 봐도 큰 문제 없다.
range(start,end,step)으로 얻어지는 range 객체도 iterable 임 (interator는 아님).
2023.06.07 - [Programming] - [Python] range and enumerate
[Python] range and enumerate
range 란엄밀하게 애기하면, range 는 숫자들의 immutable sequence (=iterable)를 나타내는 built-in type이다. 즉, 흔히 built-in function으로 애기하는 range() 는 사실은 range class의 instance를 생성하는 생성자에
dsaint31.tistory.com
collection.abc 의 Iterable abstract base class로 abstraction 되어 있음.
iterate는 반복 또는 순회라고 번역되며,
python 에서는
collection 내의 각 item 들을 처음부터 끝까지 하나씩 처리하는 것을 의미한다.
데이터들을 묶어서 관리하는 데 사용되는 list, tuple, dictionary, set 과 string, 심지어 file에 접근하는 wrapper object 모두 collection.Iterable의 subclass 이며,for문을 통해 iteration이 가능하다.
from collections.abc import Iterable
cs = (list, tuple, set, dict)
for a in cs:
print(f'{a.__name__} is a subclass of Iterable', issubclass(a, Iterable))
Iterable는
자신을 iterate하기 위해 사용되는 일종의 view에 해당하는 Iterator를 생성 및 반환할 수 있다.
이 때, Iterator 객체를 얻기 위해 사용되는 함수가 iter()함수이고
실제적으로는 Iterable object의 __iter__() special method가 사용됨.
만약 custom iterable object를 만든다면,
def class를 통해 클래스를 만들면서,
자신에 대한Iterator를 반환하는__iter__(self)special method를 구현하면 된다.
Iterator
- built-in function
iter()에 iteration의 대상이 될IterableObject를 넘겨주거나,
해당IterableObject의__iter__()special method로 얻어짐. - 자신의 special method
__next__()를 통해 "가지고 있는 elements에서의 iteration이 가능"함.
또는 built-in functionnext()에 해당Iterator의 object를 argument로 넘겨주는 방식으로도 사용가능
(이 방법도 내부적으로는__next__()를 사용함.)- 모든 element가
__next__()를 통해 반환되고 나면,
이후 해당 method 호출 시StopIterationExcpetion이 발생.
- 모든 element가
IterableObject와 마찬가지로for문에서in뒤에 놓여져서 iteration이 가능함.
duck-typing에 의해, __iter__()와 __next__()를 가지는 class의 객체로 iterator를 구현할 수 있음.
list 등이 메모리에 모든 값이 이미 evalution되어 저장되는 것과 달리,
Iterator는 __next__()의 호출될 때 필요한 값을
비로서 evaluation하는 lazy evaluation이 가능함.
for문으로 살펴본 Iterable과 Iterator의 관계는 다음과 같음.
다음과 같이 for문으로 iteration을 수행하면
for element in iterable_object:
print(element)
실제로는 아래와 같은 동작이 이루어진다고 생각하면 된다.
# iter() 통해 iterator 얻어냄
iterator_object = iter(iterable_object)
while True:
# next() 통해, Iterator에서 다음 element 를 얻어냄.
try:
element = next(iterator_object)
print(element)
# 다음 element 가 없을 경우 StopIteration Exception 발생
except StopIteration:
break
Custom Iterable and Iterator
다음과 같이 special methods들을 overriding하여 Custom Iterable 과 Iterator 를 만들 수 있음.
class DsIterable: #Iterable 이면서 Iterator임.
def __init__(self, src_seq):
self.src = src_seq
self._current = 0
def __iter__(self): # Iterable
return self # 자신에 대한 Iterator객체 반환
def __next__(self): # Iterator
current = self._current
self._current = self._current + 1
if self._current > len(self.src):
raise StopIteration
return self.src[current]
위에서 만든 Iterable로 for문을 사용하면 다음과 같음.
src = [1,2,3,4]
iter = DsIterable(src)
for i in iter:
print(i)
[Python] special methods and operator overloading
Special Methods사용자가 직접 호출하는 경우가 거의 없고, 간접적으로 호출이 됨.즉, 개발자(사용자)가 over-riding을 통해 구현은 하지만 직접 호출하는 경우가 거의 없고,개발자가 다른 built-in function
ds31x.tistory.com
Generator
generator는
주로 generator를 생성하는 function를 가르키거나,
"generator iterator 자체" 를 지칭하기도 함.
yield를 이용한 function으로 구현되거나,- collection에 대해
yield from을 사용한 function으로 구현되거나 tuple을 이용한 comprehension을 통해 generator expression을 이용.
A generator is something that you can iterate over (for us, usually using for)
but whose values are produced only as needed (lazily).
range와 마찬가지로
Generator도 lazy evalution을 수행함.
일반적으로 iterable의 경우,
해당 collection에서 가지고 있는 모든 item을 memory에 할당하여 관리하는 방식을 사용하는데
이 경우 매우 많은 item을 가질 경우 iterable object의 memory size가 커지게 됨.
이같은 단점을 해결하기 위해 제안된 generator iterator는
동적으로 element를 요청받을 때 하나씩 생성하여 내보내는 iterator로
아주 적은 크기의 item을 가지는 iterable 보다는 memory를 더 차지하지만,
많은 양의 item을 가지는 경우에는 보다 적은 크기의 memory만을 효율적으로 사용한다는 장점을 가짐.
필요할 때에 item을 생성하는 generator는
처음부터 다시 iteration을 하려면
generator를 재생성해야하는 단점이 있음.
- 여러번 iterate를 처음부터 해야하는 경우엔, list 등의 iterable을 생성하는게 보다 효과적임..
generator와 비슷한 lazy evaluatoin의 대표적인 예로는 Built-in function인range()를 들 수 있다.range는 Python 3.x에서generator인 range object를반환한다.
(Python 2.x 에서는 실제로 모든 item을 memory에 적재한list를 반환함)
단, range 객체는 여러차례 재사용이 가능함: zip와 generator는 재사용이 안되어 다시 호출하여 생성해야하는것과 차이.
참고로, generator는 값을 반환해주는 return 대신에 yield 함수를 통해 현재 item을 반환해준다.
값을 반환하고 나서 종료가 되는 return과 달리
yield는 값을 반환해주지만,
해당 함수를 종료하지 않고 상태를 그대로 유지한다.
때문에 이후 해당 함수가 다시 호출되는 경우, 이전 상태에서 이어서 처리가 이루지는 동작특성을 가지며, 이를 통해 generator를 구현할 수 있다.
yield를 이용한 function으로 구현
다음은 간단한 generator의 구현 예제로 0부터 generator iterator를 생성시 넘겨준 end argument 값까지를 반환해주는 일종의 range와 비슷한 object를 만드는 법을 보여줌.
def ds_get_generator(end):
for i in range(0, end+1):
yield i
g = ds_get_generator(3)
for c in g:
print(c)
위의 코드의 하단부의 for문에서 0~3까지를 한 줄씩 출력되는 것을 확인할 수 있음.
sys.getsizeof(g)를 통해 차지하고 있는 memory size를 비교해볼 수 있음.
이를 이용하여 5000개 정도의 숫자를 item으로 가지는iterable과generator를 비교해보라.
iterable 객체 전체를 사용하는 yield from
앞서 살펴본 경우, for문으로 item 하나씩 yield로 반환(or 전달)해주는 방식에
추가적으로 iterable object에 대한 generator iterable을 생성하는 yield from이 Python 3.3 부터 추가됨.
def ds_get_generator(end):
l = range(0, end+1)
yield from l
g = ds_get_generator(3)
for c in g:
print(c)
generator expression 으로 구현
2023.06.06 - [Programming] - [Python] List Comprehension
[Python] List Comprehension
List ComprehensionList comprehension is an expression(표현식) that transforms a collection (not necessarily a list) into a list.list를 생성하는 expression 으로, 원본이 되는 collection 의 모든 item 혹은 일부 item들에 대해 같은 op
dsaint31.tistory.com
참고: range vs. iterator vs. generator
| range | iterator | generator | |
| 목적 | 고정된 숫자 sequence | iteration을 제어 | 유연한 값 생성 및 제어 |
| lazy evaluation (지연평가) | Yes | Yes | Yes |
| next() 의 인자로 넘겨질 수 있나? | No | Yes | Yes |
| 상태 저장 가능한가? | No | Yes (내부상태 기억 가능) |
Yes (함수 내 지역변수 유지) |
| 중간 제어 (if, break, return 등) 가능한가? | No | 어느정도 가능하나 직관적이지 않음 |
Yes |
| 무한 생성 가능한가? | No | 가능하나 직관적이지 않음 | 가능 |
| 구현 방식 | built-in | class 에서 duck-typing이용 __next__() |
yield, yield from 사용하는 함수 generator comprehension |
expression의 값을 구하는 방식은 다음의 두가지가 있음:
- 필요할 때에 비로서 값을 구하는 lazy evaluation
- exporession을 실행하자마자 그 즉시 값을 구하는 경우를 eager evaluation임.
일반적으로 Python에서는 eager evaluation이 기본이지만, range, iterator, generator 처럼 매우 큰 데이터셋에 대한 순회등을 해야하는 경우에는 lazy evaluation을 사용함: 메모리 효율성과 계산 효율성 등을 위해 laze evaluation이 사용된다.
'Programming' 카테고리의 다른 글
| [Programming] Application Programming Interface (API) (0) | 2023.06.08 |
|---|---|
| [Python] range and enumerate (0) | 2023.06.07 |
| [Python] Comprehension (list, dict, set) and Generator Expression (0) | 2023.06.06 |
| [Python] Assignment와 Shallow Copy, Deep Copy (0) | 2023.06.05 |
| [Programming] Garbage Collection (GC) (0) | 2023.06.05 |