◎ Python/파이썬 심화 (책)

[파이썬 심화] 9. 여러 문장을 묶어 반복 실행하기

Reo 2022. 8. 31. 20:13
반응형

반복형(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, 문용준/문성혁 저

 

반응형