기본 데이터 구조

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

< 간단한 기본 데이터 타입 | 목차 | 제어문 >

 

파이썬의 간단한 데이터 타입인 int, float, complex, bool, str 등을 살펴 봤습니다. 파이썬은 다른 데이터 타입을 포함할 수 있는 복합 데이터 타입 몇 개를 기본으로 가지고 있습니다. 복합 데이터 타입은 다음과 같습니다:

타입 설명
list [1, 2, 3] 순서가 있는 모음
tuple (1, 2, 3) 변경 불가능한 순서가 있는 모음
dict {'a':1, 'b':2, 'c':3} 순서없는 (키,값) 매핑
set {1, 2, 3} 순서없는 고유한 값들의 모음

테이블에서 보듯이 괄호, 대괄호, 중괄호는 어떤 데이터 타입이 만들어질지 결정합니다. 이 구조들을 여기에서 간단하게 살펴 보겠습니다.

리스트

리스트는 파이썬의 기본 복합 데이터 타입으로 순서가 있고 변경 가능합니다. 리스트는 대괄호 사이에 콤마로 값을 나열하여 정의합니다. 예를 들어, 다음은 소수로 이루어진 리스트입니다:

L = [2, 3, 5, 7]

리스트는 유용한 속성과 메서드를 많이 가지고 있습니다. 다음은 이 중에 가장 많이 사용하는 것중 일부입니다:

# 리스트의 길이
len(L)
4
# 리스트 끝에 추가
L.append(11)
L
[2, 3, 5, 7, 11]
# 리스트끼리 연결
L + [13, 17, 19]
[2, 3, 5, 7, 11, 13, 17, 19]
# sort() 메서드는 리스트 자체의 정렬을 바꿉니다.
L = [2, 5, 1, 6, 3, 4]
L.sort()
L
[1, 2, 3, 4, 5, 6]

이외에도 아주 많은 내장 메서드가 많이 있습니다. 자세한 내용은 파이썬 온라인 문서를 참고하세요.

앞에서 하나의 데이터 타입으로 이루어진 경우를 보았는데 파이썬의 복합 타입의 강력한 기능 중 하나는 어떤 타입의 객체도 포함시킬 수 있다는 것입니다. 심지어 다른 복합 타입도 가능합니다. 예를 들어:

L = [1, 'two', 3.14, [0, 3, 5]]

이런 유연성은 파이썬의 동적 타입 시스템 덕분입니다. C 같은 정적 타입의 언어에서 이런 복합 타입을 만들려면 굉장히 복잡합니다! 리스트는 다른 리스트를 원소로 가질 수 있습니다. 이런 유연성은 파이썬 코드를 비교적 빠르고 쉽게 쓸 수 있도록 도와주는 핵심적인 요소입니다.

지금까지 리스트 전체를 다루는 경우를 생각했습니다. 또 다른 핵심적인 기능은 각 원소를 접근하는 방법입니다. 파이썬에서는 이를 인덱싱 또는 슬라이싱이라 하며 앞으로 살펴 보겠습니다.

리스트 인덱싱과 슬라이싱

파이썬의 복합 타입에서 하나의 원소에 접근하기 위해서는 인덱싱을 사용하고 여러개의 원소를 선택하기 위해서는 슬라이싱을 사용합니다. 잠시 후에 보게되겠지만 둘 다 대 괄호를 사용합니다. 소수로 구성된 리스트를 만들어 보죠:

L = [2, 3, 5, 7, 11]

파이썬은 0을 시작되는 인덱싱을 사용하므로 첫 번쨰와 두 번째 원소를 선택하려면 다음과 같이 합니다:

L[0]
2
L[1]
3

리스트 끝의 원소는 -1부터 시작하는 음수로 선택할 수 있습니다:

L[-1]
11
L[-2]
7

인덱싱 법칙을 다음 그림에 나타내었습니다:

list-indexing

이 그림에서 리스트에 있는 값은 상자 안에 큰 숫자로 나타나 있고 리스트의 인덱스는 상자 위와 아래에 작은 숫자로 표시했습니다. 인덱스 2 다음에 있는 값이 5이기 때문에 L[2]는 5가 됩니다.

인덱싱이 리스트에 있는 한 개의 값을 추출하는 것을 의미하고 슬라이싱은 여러 개의 값을 접근하여 서브 리스트를 만듭니다. 시작 인덱스(포함)와 종료 인덱스(미포함)를 콜론으로 연결하여 서브 리스트를 지정합니다. 예를 들어 이 리스트의 처음 세 개의 원소를 가져오려면 다음과 같이 씁니다:

L[0:3]
[2, 3, 5]

앞의 그림에서 03이 놓인 위치를 확인해 보세요. 슬라이싱은 이 인덱스 사이의 값들을 가져옵니다. 첫 번째 인덱스를 쓰지 않으면 0으로 간주하므로 다음과 같이 써도 동일합니다:

L[:3]
[2, 3, 5]

비슷하게 마지막 인덱스를 쓰지 않으면 리스트의 길이가 기본값이 됩니다. 마지막 세 개의 원소는 다음과 같이 얻을 수 있습니다:

L[-3:]
[5, 7, 11]

마지막으로 세 번째 숫자를 지정하여 건너 뛰기를 지정할 수 있습니다. 예를 들어 리스트에서 두 번째 원소마다 선택하려면 다음과 같이 씁니다:

L[::2] # L[0:len(L):2]와 동일합니다
[2, 5, 11]

음수로 건너 뛰기를 지정하면 뒤집은 리스트를 만드는데 유용합니다:

L[::-1]
[11, 7, 5, 3, 2]

인덱싱과 슬라이싱은 원소를 접근하는 것은 물론 값을 지정하는데도 사용할 수 있습니다. 사용 방법은 예상과 다르지 않습니다:

L[0] = 100
print(L)
[100, 3, 5, 7, 11]
L[1:3] = [55, 56]
print(L)
[100, 55, 56, 7, 11]

이와 비슷한 슬라이싱 기법이 (나중에 간략히 소개할) 넘파이(NumPy)나 판다스(Pandas)같은 다른 데이터 과학 패키지들에서도 사용됩니다.

지금까지 파이썬 리스트와 순서가 있는 복합 타입에서 어떻게 원소를 접근하는지 보았습니다. 이제 앞서 언급한 다른 세 가지 표준 복합 데이터 타입을 살펴 보겠습니다.

튜플

튜플(Tuple)은 리스트와 여러가지 면에서 비슷하지만 대괄호 대신 소괄호를 사용하여 정의합니다:

t = (1, 2, 3)

튜플은 아무런 괄호 없이도 만들 수 있습니다:

t = 1, 2, 3
print(t)
(1, 2, 3)

앞서 소개한 리스트처럼 튜플은 길이를 가지고 있고 각 원소는 대괄호 인덱싱을 사용하여 선택할 수 있습니다:

len(t)
3
t[0]
1

튜플과 리스트의 가장 주요한 차이점은 튜플이 수정 불가능한 타입이라는 것입니다. 튜플은 한 번 만들어지면 크기와 내용을 바꿀 수 없습니다:

t[1] = 4
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)
    
<ipython-input-46-87b0f225887f> in ()
----> 1 t[1] = 4
    
    
TypeError: 'tuple' object does not support item assignment
t.append(4)
---------------------------------------------------------------------------

AttributeError Traceback (most recent call last)

<ipython-input-47-ada7ed8a579e> in ()
----> 1 t.append(4)

AttributeError: 'tuple' object has no attribute 'append'

튜플은 파이썬 프로그램에서 특히 여러 개의 값을 반환하는 함수에서 자주 사용합니다. 예를 들어 부동소수 객체의 as_integer_ratio() 메서드는 분자와 분모를 반환합니다. 이 두 개의 값은 튜플의 형태로 전달됩니다:

x = 0.125
x.as_integer_ratio()
(1, 8)

복수개의 반환값은 다음과 같이 개별적으로 할당할 수 있습니다:

numerator, denominator = x.as_integer_ratio()
print(numerator / denominator)
0.125

리스트를 소개하면서 말한 인덱싱과 슬라이싱이 다른 메서들과 동일하게 튜플에도 적용됩니다.
전체 메서드 리스트는 온라인 파이썬 문서를 참고하세요.

딕셔너리

딕셔너리(Dictionary)는 파이썬 내부 구현의 기본 구성을 만드는 아주 유연한 키, 값 매핑입니다. 중괄호 안에 키:값 형태로 콤마로 구분된 리스트를 나열하여 만듭니다:

numbers = {'one':1, 'two':2, 'three':3}
numbers
{'one': 1, 'two': 2, 'three': 3}

리스트와 튜플에서 사용했던 인덱싱 방식을 사용해 아이템을 선택하고 값을 저장할 수 있습니다. 다만 여기서는 인덱스가 0부터 시작하는 숫자가 아니고 딕셔너리에 있는 키가 됩니다:

# 키를 통해 값을 얻어 옵니다.
numbers['two']
2

새로운 아이템을 저장하는 것도 동일한 인덱스를 사용합니다:

# 새로운 키:값 쌍을 추가합니다.
numbers['ninety'] = 90
print(numbers)
{'one': 1, 'two': 2, 'three': 3, 'ninety': 90}

딕셔너리는 설계 자체가 입력 파라미터에 대한 어떤 순서도 기억하지 않도록 되어 있습니다. 순서가 없기 때문에 매우 효율적으로 딕셔너리가 구현되어 있어서 딕셔너린의 크기에 관계없이 임의의 원소에 접근하는 속도가 매우 빠릅니다(이에 대해 궁금하다면 해시 테이블 개념을 찾아보세요). 딕셔너리의 전체 메서드는 파이썬 문서를 참고하세요.

집합

네 번째 기본 복합 타입은 순서없는 고유한 아이템을 담는 집합(set)입니다. 리스트와 튜플과 비슷하게 정의하지만 딕셔너리처럼 중괄호를 사용합니다:

primes = {2, 3, 5, 7}
odds = {1, 3, 5, 7, 9}

수학의 집합과 친숙하다면 합집합, 교집합, 차집합, 대칭차집합 등을 알고 있을 것입니다. 파이썬의 집합은 기본적으로 이 모든 연산을 메서드나 연산자로 제공합니다. 각각에 대해 동일한 두 가지 방식을 설명하겠습니다:

# 합집합: 둘 중 하나에 있는 아이템
primes | odds # 연산자로
primes.union(odds) # 메서드로
{1, 2, 3, 5, 7, 9}
# 교집합: 양쪽에 모두 있는 아이템
primes & odds # 연산자로
primes.intersection(odds) # 메서드로
{3, 5, 7}
# 차집합: primes에 있지만 odds에 없는 아이템
primes - odds # 연산자로
primes.difference(odds) # 메서드로
{2}
# 대칭차집합: 한 쪽에만 있는 아이템
primes ^ odds # 연산자로
primes.symmetric_difference(odds) # 메서드로
{1, 2, 9}

더 많은 집합 메서드와 연산자가 있습니다. 역시 파이썬 온라인 문서를 참고하세요.

전문 데이터 구조

파이썬에는 몇몇 유용한 다른 데이터 구조를 가지고 있습니다. 이들은 기본 collections 모듈 아래에서 찾을 수 있습니다. 컬렉션 모듈에 관한 전체 문서는 파이썬 온라인 문서를 참고하세요. 여기에서 다양한 종류의 객체를 둘러 볼 수 있습니다.

특히 저는 다음이 이따금 유용했습니다:

  • collections.namedtuple: 튜플과 같지만 값에 이름이 있습니다
  • collections.defaultdict: 딕셔너리와 같지만 키를 지정하지 않으면 사전에 지정한 기본 키가 할당됩니다.
  • collections.OrderedDict: 딕셔너리와 같지만 키의 순서가 유지됩니다

표준 컬렉션 타입들을 보았다면 이런 확장된 기능을 사용하는 것도 잘 이해할 수 있습니다. 온라인 문서를 읽어 보는 것이 가장 좋습니다.

 

< 간단한 기본 데이터 타입 | 목차 | 제어문 >

답글 남기기

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

WordPress.com 로고

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

Google+ photo

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

Twitter 사진

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

Facebook 사진

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

w

%s에 연결하는 중

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