리스트 내포

이 노트북은 제이크 반더플라스(Jake VanderPlas)의 A Whirlwind Tour of Python(OReilly Media, 2016)를 기반으로 만들어졌습니다. 이 내용은 CC0 라이센스를 따릅니다. 전체 노트북의 목록은 https://github.com/rickiepark/WhirlwindTourOfPython 에서 볼 수 있습니다.

< 반복자 | 목차 | 제너레이터 >

 

파이썬 코드를 읽다보면 리스트 내포라 불리는 간결하고 효율적인 구조를 보게 될 것입니다. 처음 사용한다면 이 기능이 파이썬을 사랑하게 만들어 줄 것입니다. 다음과 같이 사용합니다:

[i for i in range(20) if i % 3 > 0]
[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]

이 결과는 3의 배수를 제외한 숫자의 리스트입니다. 처음엔 조금 혼란스러울지 모르지만 파이썬에 익숙해지면 리스트 내포를 쓰고 읽는 것이 아주 자연스러워질 것입니다.

기본적인 리스트 내포

리스트 내포는 리스트를 만드는 for 루프를 짧고 읽기 쉬운 한 라인으로 압축하는 기술입니다. 예를 들어 12까지 정수의 제곱을 리스트로 만드는 루프가 있습니다:

L = []
for n in range(12):
    L.append(n ** 2)
L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]

이와 동일한 리스트 내포는 다음과 같습니다:

[n ** 2 for n in range(12)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]

다른 많은 파이썬 명령문처럼 평범한 영어로 이 코드의 의미를 읽을 수 있습니다. “12까지 n마다 n의 제곱으로 구성된 리스트를 만듭니다(square of n for each n up to 12)”.

기본적인 문법은 [expr for var in iterable]입니다. expr은 유효한 표현식이고 var는 변수 이름, iterable은 반복 가능한 파이썬 객체입니다.

중복 반복

이따금 하나의 값으로된 리스트가 아니라 두 개의 값으로된 리스트를 만들 때가 있습니다. 이렇게 하려면 간단히 다른 for 문을 내포 안에 추가하면 됩니다:

[(i, j) for i in range(2) for j in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
[(i, j) for i in range(2) for j in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]

두 번째 for 식은 결과 리스트에서 빠르게 변하는 안쪽 인덱스로 작동합니다. 이런 종류의 생성 코드는 세 개, 네 개 또는 그 이상의 반복자를 내포 안에 둘 수 있지만 어느 순간 코드를 읽기 힘들어질 것입니다!

조건부 반복

표현식 끝에 조건절을 추가해서 반복을 제어할 수 있습니다. 이 절의 처음 예제에서 1에서 20까지의 수를 반복하되 3의 배수는 제외했습니다. 이 예제를 다시 보고 명령문을 잘 살펴 보세요:

[val for val in range(20) if val % 3 > 0]
[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]

표현식 (i % 3 &gt; 0)val이 3으로 나누어 떨어지지 않는한 True로 평가됩니다. 여기에서도 영어로 그 의미를 바로 이해할 수 있습니다. “20까지 각 숫자에서 각 값이 3으로 나누어 떨어지지 않는 경우만 리스트로 구성합니다”. 이 식과 친숙해지면 동일한 루프 문법보다 훨씩 쓰기 쉬워 집니다(한 눈에 이해하기도 쉽습니다):

L = []
for val in range(20):
    if val % 3:
        L.append(val)
L
[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]

조건부 값

C 프로그래밍을 해보았다면, ? 연산자를 사용한 한 줄짜리 조건식에 익숙할 것입니다:

int absval = (val < 0) ? -val : val

파이썬은 이와 매우 비슷한 것을 가지고 있습니다. 주로 리스트 내포, lambda 함수와 간단한 표현식이 필요한 곳에 자주 사용됩니다:

val = -10
val if val >= 0 else -val
10

이는 내장 함수 abs()와 기능이 똑같지만 리스트 내포에 들어가면 재미있는 것을 만들 수 있습니다. 조금 복잡하지만 다음과 같이 쓸 수 있습니다:

[val if val % 2 else -val
 for val in range(20) if val % 3]
[1, -2, -4, 5, 7, -8, -10, 11, 13, -14, -16, 17, 19]

리스트 내포에 for 표현식 전에 줄바꿈을 했습니다. 파이썬에서 이는 문법에 맞으므로 리스트 내포를 나누어 읽기 편하게 만들어 줍니다. 리스트를 만드는데 3의 배수는 제외하고 2의 배수는 모두 음수로 만드는 작업입니다.

리스트 내포의 동작을 이해했다면 다른 타입의 내포도 이해하기 쉽습니다. 문법은 거의 비슷합니다. 다른 것은 사용할 타입의 괄호입니다.

예를 들어 중괄호를 사용하여 셋 내포set을 만들 수 있습니다:

{n**2 for n in range(12)}
{0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121}

set은 중복을 포함하지 않는 집합이란 걸 기억하세요. 셋 내포는 이 규칙에 따라 중복을 제거합니다:

{a % 3 for a in range(1000)}
{0, 1, 2}

조금 변형해서 콜론(:)을 추가하면 딕셔너리 내포를 만들 수 있습니다:

{n:n**2 for n in range(6)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

마지막으로 대괄호 대신 소괄호를 사용하면 제너레이터 표현이라는 것이 만들어 집니다:

(n**2 for n in range(12))
<generator object  at 0x10fa1d258>

제너레이터 표현식은 당장 모든 엘리먼트를 만드는 것이 아니라 필요할 때 생성하는 리스트 내포입니다. 여기서 이 단순성이 파이썬의 뛰어난 성능이라고 착각하게 만듭니다. 다음 절에서 자세히 살펴 보겠습니다.

 

< 반복자 | 목차 | 제너레이터 >

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중

This site uses Akismet to reduce spam. Learn how your comment data is processed.