03. 리스트(List), 튜플(Tuple), 딕셔너리(Dictionary), 셋(Set)

안녕하세요 이전 포스팅 애서는 Pyhton기본 자료형연산에 대해서 얘기를 나눠봤습니다. 이번 포스팅에서는 실제 데이터를 핸들링 하기 위해 필수적으로 알아야 할 리스트, 튜플, 딕셔너리, 셋(집합) 형태의 데이터들 특징과 어떻게 핸들링 하는지에 대해서 다뤄보겠습니다.

  • 리스트, 튜플, 딕셔너리, 셋 의 특징 정리
  • Mutable vs Immutable 정리
  • Orderded vs Unordered 정리

리스트, 튜플, 딕셔너리, 셋(집합) 만들기

일단 여러가지 케이스로 만들어 보고, 특징을 파악해 보겠습니다.

리스트(List) 예시
1
2
3
4
5
6
empty_list = []
empty_list = list()
int_list = [1, 2, 3, 4]
name_list = ['name_a', 'name_b', 'name_c', 'name_d']
int_name_list = [1, 'name_a', 2, 'name_b', 3, 'name_c', 4, 'name_d']
list_in_list = [1, 2, 3, ['name_a', 'name_b', 'name_c']]
튜플(Tuple) 예시
1
2
3
4
5
6
7
empty_tup = ()
empty_tup = tuple()
one_tup = (1,) # 콤마 붙여줘야 함
name_tup = ('name_a', 'name_b', 'name_c', 'name_d')
name_tup2 = 'name_a', 'name_b', 'name_c', 'name_d'
int_name_tup = (1, 'name_a', 2, 'name_b', 3, 'name_c', 4, 'name_d')
tup_in_tup = (1, 2, 3, ('name_a', 'name_b', 'name_c'))
딕셔너리(Dictionary) 예시
1
2
3
4
5
6
empty_dict = {}
empty_dict = dict()
example_dict = {'name': 'keunbit', 'blog_addr': 'https://keunbit.blog/', 'born_year': 1994}
key_int_dict = {1: 'You', 2: 'need', 3: 'Python'}
lang_dict = {'lang_list': ['Python', 'JavaScript'], 'lang_tup': ('Python', 'JavaScript')}
dict_in_dict = {'name': 'keunbit', 'born_year': 1994, 'more': {'blog': 'https://keunbit.blog/', 'github': 'https://github.com/keunbit'}}
셋(Set) 예시
1
2
3
4
5
6
7
8
9
10
11
empty_set = set()
example_set = set('Python')
list_to_set = set([1, 2, 3, 4])
tuple_to_set = set(('name_a', 'name_b', 'name_c', 'name_d'))
dict_to_set = set({'name': 'keunbit', 'blog_addr': 'https://keunbit.blog/', 'born_year': 1994})

print(f"empty_set => {empty_set}")
print(f"example_set => {example_set}")
print(f"list_to_set => {list_to_set}")
print(f"tuple_to_set => {tuple_to_set}")
print(f"dict_to_set => {dict_to_set}")
empty_set => set()
example_set => {'h', 'n', 't', 'y', 'o', 'P'}
list_to_set => {1, 2, 3, 4}
tuple_to_set => {'name_b', 'name_a', 'name_d', 'name_c'}
dict_to_set => {'born_year', 'blog_addr', 'name'}

우선 여기까지 각각의 특징을 한 번 보겠습니다.

  • 리스트
    • list() 로 비어있는 리스트를 선언할 수 있다
    • 대괄호 []로 감싸 주고 각 요소들은 콤마 ,로 구분한다.
    • 리스트에 저장되는 요소들은 어떠한 자료형도 포함시킬 수 있다.
  • 튜플
    • tuple() 로 비어있는 튜플을 선언할 수 있다.
    • 소괄호 ()로 감싸 주고 각 요소들은 콤마 ,로 구분한다.
    • 단 1개의 요소만 가질 때는 요소뒤에 콤마 ,를 반드시 붙여야 한다.
    • 변수에 선언할 때 괄호가 없어도 튜플 형태로 선언할 수 있다.
  • 딕셔너리
    • dict() 로 비어있는 딕셔너리를 선언할 수 있다.
    • {Key1: Value1, Key2: Value2, Key3, Value3, …} 처럼 Key와 Value의 쌍 여러개가 {}로 둘러싸여 있다.
    • Key에는 변하지 않는 값이며 중복될 수 없다. 반면에 Value는 변하지 않는 값을 사용할 수 있다.
    • Value에는 Tuple과 List 자료형 그리고 Dictionary를 넣을 수 있다.
  • 셋(집합)
    • set() 로 비어있는 셋을 선언할 수 있다.
    • 중복을 허용하지 않는다.
    • 순서가 없다. (Python -> h, n, t, y, o , P 로 들어감)

우선 위 코드 예시로는 저정도 특징을 알 수 있을 것 같은데요. 좀 더 중요한 얘기를 해보겠습니다.

리스트, 튜플, 딕셔너리, 셋 에 대해서 중요한 몇가지 관점 에서 비교해 보겠습니다.

Ordered(순서 있음) vs Unordered(순서 없음)

순서의 유무가 무슨 의미이지 싶으실텐데요. 데이터를 조회(찾기) 할 때 차이가 있습니다.

  • 순서가 있으면 인덱싱, 슬라이싱 으로 데이터를 조회할 수 있다. 단, Dictionary의 경우 Hash Table 이기 때문에 key값을 통해 데이터를 가져온다. (List, Tuple, Dictionary)
  • 순서가 없으면 인덱싱, 슬라이싱 은 불가능하기 때문에, list, tuple로 변환 후 조회할 수 있다. (Set)

Ordered - 인덱싱과 슬라이싱(List, Tuple)

인덱싱슬라이싱에 대해서 잠깐 짚고 넘어가겠습니다.

리스트, 튜플 인덱싱과 슬라이스
1
2
3
4
5
6
7
list_sample = [1, [2, 3], 4, 5]
tuple_sample = (6, 7, (8, 9), 10)
print(f"list_sample의 0의 인덱스 값은 list_sample[0] {list_sample[0]}")
print(f"list_sample의 마지막 인덱스 값은 list_sample[-1] {list_sample[-1]}")
print(f"tuple_sample의 1의 인덱스 값은 tuple_sample[1] {tuple_sample[1]}")
print(f"list_sample의 0~3 인덱스 값은 list_sample[0:3] {list_sample[0:3]}")
print(f"tuple_sample의 뒤에서 2번째부터 끝까지 인덱스 값은 tuple_sample[-2:] {tuple_sample[-2:]}")
list_sample의 0의 인덱스 값은 list_sample[0] 1
list_sample의 마지막 인덱스 값은 list_sample[-1] 5
tuple_sample의 1의 인덱스 값은 tuple_sample[1] 7
list_sample의 0~3 인덱스 값은 list_sample[0:3] [1, [2, 3], 4]
tuple_sample의 뒤에서 2번째부터 끝까지 인덱스 값은 tuple_sample[-2:] ((8, 9), 10)

여기서 정리할 수 있는 것은

  1. Python은 0부터 숫자를 세기 때문에 첫번째 0요소를 조회할 땐 인덱스 값을 0으로 해야 한다는 것입니다.
  2. 슬라이싱은 : 기호를 사용해서 특정 인덱스:인덱스 를 통해 특정 범위의 데이터를 조회할 수 있습니다.

Ordered - Key값으로 조회(Dictionary)

자 그럼 순서가 없는 딕셔너리와, 셋은 어떻게 조회할까요?

딕셔너리 데이터 조회하기
1
2
3
dict_sample = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
print(dict_sample['key1'])
print(dict_sample[0]) # 에러
value1
----> 4 print(dict_sample[0])
KeyError: 0

딕셔너리의 경우는 key 값을 통해서 value1의 값을 조회하였습니다. 반면에 인덱스 형태로 0의 값을 주어 찾으려고 하게 되면 keyError라는 에러 메시지를 띄우게 됩니다. 위에서 Hash 를 통해 데이터를 조회한다고 했는데요. 이렇게 자료구조를 해쉬 방식으로 저장하게 되면, 나중에 데이터를 조회할 때 속도 측면에서 굉장한 장점을 가지게 됩니다.

Unoreded - 리스트,튜플로 변환 후 조회(Set)

셋 데이터 조회하기
1
2
3
4
set_sample = {1, 2, 3, 4, 5}
print(list(set_sample)[1])
print(tuple(set_sample)[2])
print(set_sample[1]) # 에러
2
3
----> 4 print(set_sample[1])
TypeError: 'set' object is not subscriptable

셋(Set)의 경우 List, Tuple 형태로 변환 후 인덱스 값을 주어 찾아야 합니다.

Mutable(가변성) vs Immutable(불변성)의 관점

가변성이란 말그대로 요소의 값이 변경할 수 있다. 즉, 수정(어데이트)이 가능하다 라는 의미입니다. (그런데 요소를 추가하는 것은 또 다른 얘기입니다)

  • 튜플은 Immutable / 리스트, 딕셔너리, 셋 은 Mutable 합니다.

먼저 Mutable한 것부터 보겠습니다. Mutable 하기때문에 추가, 수정, 삭제 등의 기능을 제공합니다.

Mutable - 추가

리스트
1
2
3
4
5
6
7
8
9
list_sample = [1, 2, 3, 4, 5]
list_sample.append(6)
print(list_sample)
list_sample.extend([7,8,9]) # Nest 하게 추가하는 방법
print(list_sample)
list_sample.append([10,11,12]) # list 그대로 추가됨
print(list_sample)
list_sample += [13, 14, 15] # list 그대로 추가됨
print(list_sample)
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, [10, 11, 12]]
[1, 2, 3, 4, 5, 6, 7, 8, 9, [10, 11, 12], 13, 14, 15]

extend() 함수와 append() 예시 주목해보면 좋을 것 같습니다.

1
2
3
4
5
set_sample = {6, 7, 8, 9, 10}
set_sample.add(11)
print(set_sample)
set_sample.update([12, 13, 14]) # 여러개 추가할 때 update를 사용
print(set_sample)
{6, 7, 8, 9, 10, 11}
{6, 7, 8, 9, 10, 11, 12, 13, 14}
딕셔너리
1
2
3
4
5
dict_sample = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
dict_sample['key4'] = 'value4'
print(dict_sample)
dict_sample.update({'key5': 'value5', 'key6': 'value6'}) # 여러개 추가
print(dict_sample)
{'key1': 'value1', 'key2': 'value2', 'key3': 'value3', 'key4': 'value4'}
{'key1': 'value1', 'key2': 'value2', 'key3': 'value3', 'key4': 'value4', 'key5': 'value5', 'key6': 'value6'}

여러개를 추가할 때 update() 함수를 사용하며 셋의 경우 추가할 요소들을 []로 감싸는 것 과 딕셔너리의 경우 같은 {} 안에 key: value 형태를 맞춰서 넣어 주고 있다는 것을 주목해볼 필요가 있겠네요.

Mutable - 수정

리스트
1
2
3
list_sample = [1, 2, 3, 4, 5]
list_sample[1] = 6
print(list_sample)
[1, 6, 3, 4, 5]

셋의 경우 데이터를 수정하는 기능은 없습니다.

딕셔너리
1
2
3
4
5
dict_sample = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
dict_sample['key1'] = 'value4'
print(dict_sample)
dict_sample.update({'key2': 'value5', 'key3': 'value6'})
print(dict_sample)
{'key1': 'value4', 'key2': 'value2', 'key3': 'value3'}
{'key1': 'value4', 'key2': 'value5', 'key3': 'value6'}

딕셔너리는 update() 함수를 통해 추가, 수정도 가능하네요.

Mutable - 삭제

리스트
1
2
3
4
5
6
7
8
9
10
11
12
list_sample = [1, 2, 3, 4, 5]
del list_sample[1]
print(list_sample)
list_sample = [1, 2, 3, 4, 5]
list_sample.pop(0)
print(list_sample)
list_sample = [1, 2, 3, 4, 5]
list_sample.pop()
print(list_sample)
list_sample = [1, 2, 3, 4, 5]
list_sample.remove(3)
print(list_sample)
[1, 3, 4, 5]
[2, 3, 4, 5]
[1, 2, 3, 4]
[1, 2, 4, 5]

del, pop() 함수는 index 를 통해서 삭제한다는 것과 remove() 함수는 요소 값을 삭제하는 것 그리고 pop() 인덱스 값을 넣지 않을 경우 가장 끝에 요소를 지운다는 것을 짚고 넘어가면 좋을 것 같습니다.

1
2
3
4
5
set_sample = {6, 7, 8, 9, 10}
set_sample.remove(7)
print(set_sample)
set_sample.clear()
print(set_sample)
{6, 8, 9, 10}
set()

셋도 마찬가지로 remove() 함수를 통해서 요소 값 자체를 삭제시키네요. clear() 함수는 요소를 모두 삭제시킬 수 있습니다.

딕셔너리
1
2
3
4
5
6
7
dict_sample = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
del dict_sample['key1']
print(dict_sample)
dict_sample.pop('key2')
print(dict_sample)
dict_sample.clear()
print(dict_sample)
{'key2': 'value2', 'key3': 'value3'}
{'key3': 'value3'}
{}

딕셔너리는 del, pop(), clear() 함수를 통해서 요소를 삭제시킬 수 있습니다.

Immutable - 추가

튜플의 경우 요소의 값을 변화시키는 것을 못할 뿐 뒤에 값을 더하는 것은 가능합니다. (리스트와 동일)

튜플
1
2
3
4
set_sample1 = (1, 2, 3, 4, 5)
set_sample2 = (6, 7, 8, 9, 10)
set_sample3 = set_sample1 + set_sample2
print(set_sample3)
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

결론

정리해보겠습니다. 데이터를 핸들링하기 위해서 필수적으로 알아야 하는 데이터 자료형들의 특징에 대해서 알아봤습니다. 그리고 리스트, 튜플, 딕셔너리, 셋 에 대해서 순서가변성 의 관점에서 각각의 기능(추가, 수정, 삭제) 들도 다뤄봤습니다. 이 내용은 여기서 끝이 아니라 앞으로 개발 하시면서 계속해서 다룰것들이니 내용 잘 정리해두시면 좋을 것 같습니다.

다음 포스팅은 조건문(if), 반복문(for, while) 주제에 대해서 다뤄보겠습니다.

이상으로 이번 포스팅은 마치겠습니다. 추가 의견이나 수정이 필요한 부분이 있다면 언제든지 거침없는 피드백 부탁드립니다! 부족한 글 읽어주셔서 감사합니다!

Reference

댓글