반복형(iterable)과 반복자(Iterator)은 다르다!
반복형(iterable)이란?
말 그대로 '반복 가능한 객체'를 말한다. 특징으로 원소를 여러 개 가진 정적인 객체를 만든다.
반복자(Iterator)이란?
반복자 객체는 값을 차례대로 꺼낼 수 있는 객체를 말한다. 동적 처리를 하기 위해 별도의 핸들러를 만든 후 내부의 원소를 하나씩 꺼내 처리하는 기능을 제공한다.
사실 이렇게 봐도 다른 점이 잘 보이지 않는다. 예제로 보자. 우선 Iterable인지 Iterator인지 구별하기 위해 collections 모듈을 import한 후 상속 관계를 파악하는 issubclass 함수를 이용해 Iterable 클래스를 상속받는지, Iterator 클래스를 상속받는지 알아보자.
import collections.abc as cols
l = [1, 2, 3, 4, 5]
issubclass(type(l), cols.Iterable)
issubclass(type(l), cols.Iterator)
[결과]
True
False
리스트 클래스는 정적 처리가 가능한 반복형이지만 반복자는 아니라는 것을 알 수 있다.
그렇다면 반복자는 어떻게 만들 수 있을까? 파이썬 내장함수 iter()를 사용해 iterator 객체를 만들 수 있다.
import collections.abc as cols
l = [1, 2, 3, 4, 5]
lt = iter(l)
issubclass(type(lt), cols.Iterable)
issubclass(type(lt), cols.Iterator)
[결과]
True
True
반복자는 Iterable 클래스와 Iterator 클래스 모두 상속받는 것을 볼 수 있다.
그렇다면 반복자는 어떻게 사용할까?
import collections.abc as cols
l = [1, 2, 3, 4, 5]
lt = iter(l)
dir(lt)
[결과]
[...
'__next__',
...]
dir 함수를 이용해 lt가 어떤 메소드를 가지고 있는지 알아보자. 여기서 주목해야 할 메소드는 __next__ 메소드다. 이 메소드를 사용해 순차적으로 내놓고자 하는 값들을 내놓은 후 마지막에 StopIteration 에러를 내놓는다. 즉, 다음과 같이 사용이 가능하다.
import collections.abc as cols
l = [1, 2, 3, 4, 5]
lt = iter(l)
while True:
try:
print(next(lt))
except StopIteration:
print("끝!")
break
[결과]
1
2
3
4
5
끝!
순환 처리 배제하기
간단하게 continue를 이용해 아래 문장을 처리하지 않고 다시 반복문으로 돌아가거나 break를 사용해 순환 자체를 종료할 수 있다.
var = 1
while True:
if var == 10:
break
var += 1
if var % 2 == 0:
print(var, end=" ")
continue
[결과]
2 4 6 8 10
순환문에 else도 추가할 수 있다!
제어문에서만 else를 쓸 수 있는 것이 아니다. 순환문에서 else를 사용한다면 정상적으로 순환이 처리됐을 때 else 아래의 문장을 실행하고, 강제 종료된다면 else문이 실행되지 않는다.
var = 0
for i in range(100):
var += 1
else:
print(var, "정상 종료", sep=", ")
[결과]
100, 정상 종료
var = 0
for i in range(100):
var += 1
if var > 50:
break
else:
print(var, "정상 종료", sep=", ")
[결과]
# 강제 종료되었으므로 결괏값이 없음
다양한 원소를 갖는 객체의 원소 추출하기
인덱스 정보를 함께 가져오는 enumerate 클래스
리스트 객체가 원소와 그 원소가 속한 인덱스 정보를 함께 가져올 때는 enumerate 클래스를 사용할 수 있다.
l = [1, 2, 3, 4, 5]
for i, v in enumerate(l):
print(f"index : {i}, value : {v}")
[결과]
index : 0, value : 1
index : 1, value : 2
index : 2, value : 3
index : 3, value : 4
index : 4, value : 5
두 객체를 합쳐주는 zip 클래스
두 개의 리스트 객체를 전달해 순서 쌍을 만들기 위해 zip 클래스를 사용할 수 있다.
참고로 zip 클래스는 두 객체를 합쳐준다는 점에서 많은 곳에서 쓰인다.
l = [1, 2, 3, 4, 5]
ll = [6, 7, 8, 9, 10]
for i in zip(l, ll):
print(i)
[결과]
(1, 6)
(2, 7)
(3, 8)
(4, 9)
(5, 10)
객체의 크기가 동일하지 않을 때 합칠 수 있는 zip_longest
위의 zip 클래스는 두 객체의 크기(길이)가 동일하지 않을 때는 사용할 수 없다. 정확히는 더 작은 크기의 객체에 맞게 합쳐진다. 이럴 때 itertools 모듈 속 zip_longest를 사용할 수 있다.
import itertools as it
l = [1, 2, 3, 4]
ll = [6, 7, 8, 9, 10]
for i in it.zip_longest(l, ll):
print(i)
[결과]
(1, 6)
(2, 7)
(3, 8)
(4, 9)
(None, 10) # 없는 원소는 None으로 처리
하나의 리스트를 만들지는 않지만 연결해서 출력하는 chain
두 리스트를 위처럼 하나의 리스트로 만들지는 않지만 연달아 출력하기 위해 itertools의 chain을 사용할 수 있다.
import itertools as it
l = [1, 2, 3, 4]
ll = [6, 7, 8, 9, 10]
for i in it.chain(l, ll):
print(i, end=" ")
[결과]
1 2 3 4 6 7 8 9 10
한 리스트에서 여러 원소를 묶어주는 combinations
여러 개의 원소를 묶어 순서 쌍을 만든다. 중복 없이!
import itertools as it
l = [1, 2, 3, 4]
for i in it.combinations(l, 3): # 3개를 선택해 중복 없이 경우의 수 출력
print(i)
[결과]
(1, 2, 3)
(1, 2, 4)
(1, 3, 4)
(2, 3, 4)
한 리스트에서 여러 원소를 순서에 맞춰 묶어주는 permutations
순열과 조합! 이 경우는 순열이므로 순서를 생각해 모든 순서쌍을 출력해준다.
import itertools as it
l = [1, 2, 3, 4]
cnt = 0
for i in it.permutations(l, 3): # 3개를 선택해 순서에 따라 나열
print(i, end=", ")
cnt += 1
if cnt % 5 == 0:
print()
[결과]
(1, 2, 3), (1, 2, 4), (1, 3, 2), (1, 3, 4), (1, 4, 2),
(1, 4, 3), (2, 1, 3), (2, 1, 4), (2, 3, 1), (2, 3, 4),
(2, 4, 1), (2, 4, 3), (3, 1, 2), (3, 1, 4), (3, 2, 1),
(3, 2, 4), (3, 4, 1), (3, 4, 2), (4, 1, 2), (4, 1, 3),
(4, 2, 1), (4, 2, 3), (4, 3, 1), (4, 3, 2),
참고
- 한권으로 개발자가 원하던 파이썬 심화 A to Z, 문용준/문성혁 저
'◎ Python > 파이썬 심화 (책)' 카테고리의 다른 글
[파이썬 심화] 11. 함수 정의하기 (0) | 2022.09.02 |
---|---|
[파이썬 심화] 10. 여러 조건에 따라 기능 선택하기 (0) | 2022.09.01 |
[파이썬 심화] 8. 조건 판단에 따른 문장 선택하기 (0) | 2022.08.30 |
[파이썬 심화] 7. 할당 및 기타 문장 처리하기 (0) | 2022.08.29 |
[파이썬 심화] 6. 문서화와 주석으로 꾸미기 (1) | 2022.08.28 |
자기계발 블로그