컨테이너(Container) 자료형
1. 컨테이너 란?
1-1. 기존 저장 방식의 한계
- 지금까지 우리는 하나의 변수에 하나의 값만을 저장하여 사용해왔다.
- 하지만 이러한 방식에는 명확한 한계가 존재하는데, 다음의 예시를 살펴보자.
1. 사람들의 이름을 수집하려고 한다. 변수를 이용하여 2명의 이름을 아래와 같이 수집할 수 있다.
name1 = "kyle"
name2 = "alex"
2. 사람들이 점점 늘어난다. 변수를 이용하여 5명의 이름을 아래와 같이 수집할 수 있다.
name1 = "kyle"
name2 = "alex"
name3 = "james"
name4 = "martin"
name5 = "alice"
3. 사람들이 100명이 되면 이름을 어떻게 수집할 수 있을까? 변수를 100개 만들어야 할까? 그럼 10000명이 되면? 1억명이 되면?
- 따라서 여러 개의 데이터를 하나의 공간에 저장할 수 있는 방식이 필요해졌다. 파이썬은 컨테이너 자료형을 통해 이런 기능을 제공한다.
1-2. 컨테이너의 분류
- 컨테이너란 여러 개의 데이터를 한 곳에 저장할 수 있는 자료형을 의미한다. 이는 또 두 가지로 나누어진다.
- 순서가 있는 컨테이너(Sequence) : 데이터를 연속된 공간에 순서대로 저장하는 컨테이너 ex) 리스트, 문자열, 레인지, 튜플
- 순서가 없는 컨테이너(Non-sequence) : 데이터를 무작위의 순서로 저장하는 컨테이너 ex) 집합, 딕셔너리
✓ 순서가 있다는 것과 정렬 되었다는 것은 다르다!
예를 들어 순서가 있는 컨테이너 중 하나인 리스트 자료형은 데이터를 [1, 5, 2, 6] 과 같은 형태로 저장한다.
[1, 5, 2, 6] 은 정렬되어 있지는 않지만 1 다음에 5 다음에 2 다음에 6 과 같은 식으로 연속적으로 저장되어 있으므로 순서가 있다고 할 수 있다.
2. 리스트(List)
2-1. 리스트 란?
- 리스트는 0개 이상의 데이터를 순서 있게 저장하는 컨테이너 자료형이다.
- 변수가 하나의 상자라면, 리스트는 여러 개의 상자가 일렬로 붙어있는 것이다.
- 대괄호([])를 이용해 생성한다. 각 원소는 콤마(,)를 기준으로 구분된다.
numbers = [10, 20, 30, 40, 50]
print(numbers)
print(type(numbers))
[10, 20, 30, 40, 50]
<class 'list'>
- 리스트 안에는 다양한 자료형이 원소로 저장될 수 있다.
data = [10, 1.5, "python", False]
print(data)
[10, 1.5, 'python', False]
- 빈 리스트도 생성 가능하다.
empty = []
print(empty)
[]
- len() 내장함수를 사용하면 리스트의 길이를 알 수 있다.
numbers = [10, 20, 30, 40, 50]
print(len(numbers))
5
2-2. 리스트 연산
리스트는 덧셈(+)과 곱셈(*) 연산을 제공한다.
1. 리스트 덧셈(+)
- 두 개 이상의 리스트를 합칠 수 있다.
a = [1, 2]
b = [3, 4]
c = a + b
print(c)
[1, 2, 3, 4]
2. 리스트 곱셈(*)
- 리스트의 원소를 여러 번 반복하여 생성할 수 있다.
a = [1, 2, 3]
b = a * 3
print(b)
[1, 2, 3, 1, 2, 3, 1, 2, 3]
- 같은 원소가 여러 개 있는 리스트를 만들 때 유용하다.
a = [1] * 10
print(a)
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
2-3. 인덱싱(Indexing)
인덱스(index)란 리스트의 특정 원소가 몇 번째에 위치하는지 나타내는 숫자를 말한다. 인덱스는 리스트의 원소에 접근(조회)하거나 원소를 수정할 때 사용한다.
1. 접근(조회)
- 리스트[인덱스]의 형식으로 원소에 접근할 수 있다.
numbers = [10, 20, 30, 40, 50]
print(numbers[1]) # numbers 리스트의 1번째 원소인 20이 출력 => 원소 20은 2번째 아닌가? 왜 1번째가 20일까?
20
- 컴퓨터는 숫자를 0부터 센다!
numbers = [10, 20, 30, 40, 50]
print(numbers[0])
print(numbers[1])
print(numbers[2])
print(numbers[3])
print(numbers[4]) # 항상 마지막 원소의 인덱스는 (리스트의 길이 - 1)
10
20
30
40
50
- 음수 인덱싱도 가능하다. 인덱스를 뒤에서부터 세는 것을 의미한다.
- 단, 맨 뒤의 인덱스는 -1로 시작한다. (-0은 0과 같기 때문에 양수 인덱싱과 충돌이 생기므로 시작을 -1로 한다.)
numbers = [10, 20, 30, 40, 50]
print(numbers[-1])
print(numbers[-2])
print(numbers[-3])
print(numbers[-4])
print(numbers[-5])
50
40
30
20
10
2. 수정
- 리스트[인덱스] = 새로운 원소의 형식으로 기존 원소 값을 수정할 수 있다.
numbers = [10, 20, 30, 40, 50]
numbers[1] = -1 # 리스트의 1번째 공간에 -1을 재 할당
print(numbers)
[10, -1, 30, 40, 50]
- 당연히 음수 인덱스로도 수정할 수 있다.
numbers = [10, 20, 30, 40, 50]
numbers[-1] = 100 # 리스트의 -1번째(마지막) 공간에 100을 재 할당
print(numbers)
[10, 20, 30, 40, 100]
2-4. 슬라이싱(Slicing)
슬라이싱(Slicing)이란 리스트를 어디부터 어디까지 특정 구간을 나누어 자르는 것을 말한다.
- 리스트[start:end:step]의 형식으로 작성할 수 있다.
- start : 리스트를 자를 범위의 시작 인덱스
- end : 리스트를 자를 범위의 끝 인덱스 (이때 end 인덱스에 해당하는 원소는 포함되지 않음)
- step : 리스트를 얼마 간격으로 뛰어넘으며 자를 것인지 결정 (음수는 반대 방향을 의미)
a = [10, 20, 30, 40, 50]
# 0 1 2 3 4
# -5 -4 -3 -2 -1
# start ~ end-1 까지 자르기 (양수, 음수 인덱스 혼합 가능)
a[2:4] # [30, 40]
a[-3:-1] # [30, 40]
a[2:-1] # [30, 40]
# step을 이용해서 자르기 (음수는 반대 방향을 의미)
a[1:4:2] # [20, 40]
a[-5:-2:2] # [10, 30]
a[1:4:-1] # []
a[4:1:-1] # [50, 40, 30]
# start, end, step을 지정하지 않으면 기본값으로 자르기
a[:3] # [10, 20, 30]
a[2:] # [30, 40, 50]
a[:] # [10, 20, 30, 40, 50]
a[::-1] # [50, 40, 30, 20, 10] (리스트를 뒤집을 때 많이 사용되므로 숙지할 것)
2-5. 원소의 삽입과 삭제
파이썬의 리스트는 가변적이다. 원소를 삽입하고 삭제하는 것이 자유롭다.
1. 리스트에 원소 삽입(append)
- 리스트.append(새로운 원소)의 형식으로 작성한다.
- 리스트의 맨 마지막에 새로운 원소가 삽입된다.
a = [10, 20, 30, 40, 50]
a.append(60) # 리스트 a의 마지막에 60을 삽입
print(a)
[10, 20, 30, 40, 50, 60]
2. 리스트에서 원소 삭제(pop)
- 리스트.pop()의 형식으로 작성한다.
- 리스트의 맨 마지막 원소가 삭제된다.
a = [10, 20, 30, 40, 50]
a.pop() # 리스트 a의 마지막 원소 50을 삭제
print(a)
[10, 20, 30, 40]
- 리스트.pop(삭제할 원소의 인덱스)의 형식으로 작성하면, 특정 인덱스의 원소를 삭제할 수 있다.
a = [10, 20, 30, 40, 50]
a.pop(2) # 리스트 a의 2번째 원소 30을 삭제
print(a)
[10, 20, 40, 50]
- pop()은 삭제와 동시에, 삭제한 원소를 반환하기도 한다. 이를 변수에 할당하여 사용할 수 있다.
a = [10, 20, 30, 40, 50]
b = a.pop() # 맨 마지막 원소를 삭제하고 반환
print(b) # 50
c = [60, 70, 80, 90, 100]
d = c.pop(2) # 2번째 원소를 삭제하고 반환
print(d) # 80
50
80
3. 문자열(String)
기존에 알고있던 문자열이 사실 컨테이너 자료형이었다.
3-1. 문자열 이란?
- 문자열은 0개 이상의 문자를 순서 있게 저장하는 컨테이너 자료형이다.
- 작은 따옴표(’) 혹은 큰 따옴표(”)를 이용해 생성한다.
- 문자열은 말 그대로 연속으로 나열된 문자의 집합체라고 할 수 있다.
"python"이라고 하는 문자열은 "p", "y", "t", "h", "o", "n" 의 6개의 문자가 연속으로 나열된 집합체이다.
- 빈 문자열도 문자열이고, 원소가 1개인 문자열도 문자열이다. 또한 공백도 문자열이다.
- len() 내장함수를 사용하면 문자열의 길이를 알 수 있다.
sentence = "hello python"
print(len(sentence)) # 공백 포함 총 12 글자
12
3-2. 문자열 연산
문자열은 덧셈(+)과 곱셈(*) 연산을 제공한다.
1. 문자열 덧셈(+)
- 두 개 이상의 문자열을 합칠 수 있다.
a = "hello"
b = "python"
c = a + b
print(c)
2. 문자열 곱셈(*)
- 문자열의 원소를 여러 번 반복하여 생성할 수 있다.
a = "안녕"
b = a * 3
print(b)
안녕안녕안녕
3-3. 인덱싱(Indexing)
- 문자열도 리스트와 같이 인덱스를 통해 원소에 접근할 수 있다.
word = "python"
print(word[1]) # 문자열 word의 1번째 원소인 "y"를 출력
y
- 문자열도 음수 인덱싱이 가능하다.
word = "python"
print(word[-1]) # 문자열 word의 -1번째(마지막) 원소인 "n"을 출력
n
- 문자열은 리스트와 달리 원소를 수정할 수 없다. (문자열은 원소의 삽입, 삭제도 불가능하다.)
word = "python"
word[0] = "j"
print(word)
File "/Users/edu/test.py", line 2, in <module>
word[0] = "j"
TypeError: 'str' object does not support item assignment
- 그러면 “python”에서 “p”를 “j”로 바꿀 수 없는 것일까? ⇒ 방법은 있다!
- 하지만 이는 어디까지나 “jython”이라고 하는 새로운 문자열을 생성한 것이지, 기존의 “python”을 “jython”으로 수정한 것은 아니다.
word = "python"
new_word = "j" + word[1:] # 문자열 덧셈과 슬라이싱을 이용하여 마치 수정한 것과 같은 효과를 줄 수 있다.
print(new_word)
jython
3-4. 슬라이싱(Slicing)
- 문자열도 리스트와 같이 슬라이싱이 가능하다.
- 문자열[start:end:step]의 형식으로 작성할 수 있다.
- start : 문자열을 자를 범위의 시작 인덱스
- end : 문자열을 자를 범위의 끝 인덱스 (이때 end 인덱스에 해당하는 원소는 포함되지 않음)
- step : 문자열을 얼마 간격으로 뛰어넘으며 자를 것인지 결정 (음수는 반대 방향을 의미)
s = "abcdefghi"
# start ~ end-1 까지 자르기 (양수, 음수 인덱스 혼합 가능)
s[2:5] # "cde"
s[-6:-2] # "defg"
s[2:-4] # "cde"
# step을 이용해서 자르기 (음수는 반대 방향을 의미)
s[2:5:2] # "ce"
s[-6:-1:3] # "dg"
s[2:5:-1] # ""
s[5:2:-1] # "fed"
# start, end, step을 지정하지 않으면 기본값으로 자르기
s[:3] # "abc"
s[5:] # "fghi"
s[:] # "abcdefghi"
s[::-1] # "ihgfedcba" (문자열을 뒤집을 때 많이 사용되므로 숙지할 것)
3-5. f-string
파이썬 3.6 버전부터 지원하는 문자열 포매팅(formatting) 기능인 f-string에 대해 알아보자.
- “제 이름은 kyle 입니다.”, “제 이름은 alex 입니다.”와 같이 문자열 내의 특정 단어를 바꿔서 출력하는 경우가 있다.
- “kyle”과 “alex”에 해당하는 부분을 변수에 넣고 동적으로 변화시키며 출력해야 한다.
name = "kyle"
sentence = "제 이름은 " + name + " 입니다."
print(sentence)
제 이름은 kyle 입니다.
- 문자열 포매팅을 이용하면 더욱 깔끔하게 작성할 수 있다. 문자열 포매팅이란 문자열 안에 변수의 값을 삽입하는 방법을 말한다.
- 파이썬은 f-string이라는 문법을 통해 문자열 포매팅 기능을 제공한다.
- f"{변수}"의 형식으로 사용할 수 있다. 다음의 두 가지 규칙을 반드시 준수해야 한다.
- 따옴표의 가장 앞에 반드시 알파벳 f를 붙인다.
- 변수가 들어가는 부분은 중괄호({})로 감싼다. (감싸지 않으면 변수명 자체가 문자열로 인식된다.)
name = "kyle"
sentence = f"제 이름은 {name} 입니다." # 변수 부분은 중괄호({})로 감싸서 작성
print(sentence)
제 이름은 kyle 입니다.
- 문자열 뿐만 아니라 정수, 실수, 논리 등 다양한 자료형을 삽입할 수 있다.
name = "kyle"
age = 20
sentence = f"{name}은 {age}살 입니다."
print(sentence)
kyle은 20살 입니다.
- 연산식이나 내장 함수의 호출도 삽입할 수 있다.
name = "kyle"
age = 20
sentence1 = f"이름의 길이는 {len(name)} 입니다."
sentence2 = f"내년이 되면 {age + 1}살 입니다."
print(sentence1)
print(sentence2)
이름의 길이는 4 입니다.
내년이 되면 21살 입니다.
4. 레인지(range)
- 레인지는 연속된 정수 목록을 저장하는 컨테이너 자료형이다.
- range(start, end, step)의 형식으로 작성할 수 있다.
- start : 목록의 시작 정수 (start는 생략될 수 있으며, 생략되면 자동적으로 0부터 시작)
- end : 목록의 끝 정수 (이때 end에 해당하는 정수는 포함되지 않고 end - 1 까지만 저장)
- step : start부터 얼마나 뛰어넘으면서 end - 1까지의 정수 목록을 만들 것인지 결정 (음수는 반대 방향을 의미)
range(1, 11) # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
range(1, 11, 2) # 1, 3, 5, 7, 9
range(10, 0, -1) # 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
range(0, 5) # 0, 1, 2, 3, 4
range(5) # 0, 1, 2, 3, 4 (start가 생략되어 range(0, 5)와 같음)
- range()를 단순히 출력했을 때는 원소의 값들을 확인하기 어렵다.
a = range(1, 11)
print(a)
print(type(a))
range(1, 11)
<class 'range'>
- 하지만 분명히 range()에는 start ~ end-1 까지의 연속된 정수 목록이 담겨있다.
- 이후에 학습할 for 반복문을 이용하여 각각의 원소를 출력해볼 수 있다.
# 1 ~ 10까지의 정수 목록이 담긴 range에서 한 개씩 꺼내 출력하는 코드
for i in range(1, 11):
print(i, end=" ")
1 2 3 4 5 6 7 8 9 10
5. 컨테이너 형 변환
5-1. 문자열 → 리스트
- 문자열의 각 원소를 쪼개서 리스트의 원소로 각각 담을 수 있다.
- list() 내장함수를 이용하면 간단하게 변환 할 수 있다.
a = "python"
b = list(a)
print(b)
['p', 'y', 't', 'h', 'o', 'n']
5-2. 레인지 → 리스트
- 레인지의 각 원소를 쪼개서 리스트의 원소로 각각 담을 수 있다.
- 문자열과 마찬가지로 list() 내장함수를 이용하면 가능하다.
a = range(10)
b = list(a)
print(b)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
6. 멤버십 연산자(in, not in)
특정 원소가 컨테이너 안에 있는지 판별하는 연산자이다.
6-1. in 연산자
- 원소 in 컨테이너의 형식으로 작성하며 해당 원소가 컨테이너에 있으면 True, 없으면 False를 반환한다.
numbers = [1, 2, 3, 4, 5]
print(1 in numbers) # numbers 리스트에 원소 1이 있으므로 True
print(6 in numbers) # numbers 리스트에 원소 6이 없으므로 False
True
False
6-2. not in 연산자
- 원소 not in 컨테이너의 형식으로 작성하며 해당 원소가 컨테이너에 없으면 True, 있으면 False를 반환한다.
word = "python"
print("p" not in word) # word 문자열에 원소 "p"가 있으므로 False
print("j" not in word) # word 문자열에 원소 "j"가 없으므로 True
False
True
6-3. 조건문에서의 사용
- 주로 특정 원소가 있을 때와 없을 때의 동작을 구분하기 위해, 조건문에서 많이 사용된다.
classroom = ["kyle", "alex", "justin", "jayden"]
if "alex" in classroom:
print("alex는 출석했습니다.")
else:
print("alex는 결석했습니다.")
alex는 출석했습니다.
'Python' 카테고리의 다른 글
기초 자료구조와 로직 설계 (1) | 2024.03.23 |
---|---|
반복문(Loop) (1) | 2024.03.23 |
조건문(Condition) (0) | 2024.03.23 |
연산자(Operators) (1) | 2024.03.17 |
사용자 입력(input)과 출력(print) (0) | 2024.03.17 |