리스트, 튜플, 문자열... 이들은 모두 시퀀스 자료형이라는 공통점을 가지고 있습니다. 시퀀스 자료형은 파이썬에서 가장 자주 사용되는 자료형이며, 공통된 동작과 기능을 제공합니다. 이번 포스트에서는 시퀀스 자료형의 특징과 활용법, 특히 인덱싱과 슬라이싱에 대해 깊이 있게 알아보겠습니다.
시퀀스 자료형(Sequence Types)은 값이 연속적으로 이어진 자료형을 말합니다.
| 자료형 | 예시 | 수정 가능 |
|---|---|---|
| 리스트 | [1, 2, 3] | ✅ |
| 튜플 | (1, 2, 3) | ❌ |
| 문자열 | 'Hello' | ❌ |
| range | range(1, 5) | ❌ |
numbers = [1, 2, 3, 4, 5] # 시퀀스 객체
# ↑ ↑ ↑ ↑ ↑
# 요소들
시퀀스 자료형의 가장 큰 특징은 공통 동작과 기능을 제공한다는 점입니다.
in 연산자로 특정 값이 시퀀스에 포함되어 있는지 확인할 수 있습니다.
# 리스트
numbers = [1, 2, 3, 4, 5]
print(3 in numbers) # True
print(10 in numbers) # False
# 튜플
fruits = ('apple', 'banana', 'cherry')
print('apple' in fruits) # True
print('orange' in fruits) # False
# 문자열
text = 'Hello, Python!'
print('Python' in text) # True
print('Java' in text) # False
# range
r = range(1, 11)
print(5 in r) # True
print(15 in r) # False
not in 연산자는 특정 값이 없는지 확인합니다.
numbers = [1, 2, 3, 4, 5]
print(10 not in numbers) # True (10이 없음)
print(3 not in numbers) # False (3이 있음)
# 실용 예시
banned_words = ['욕설1', '욕설2', '욕설3']
user_input = '안녕하세요'
if user_input not in banned_words:
print('적절한 입력입니다')
else:
print('부적절한 입력입니다')
+ 연산자로 같은 자료형의 시퀀스 객체를 연결하여 새 객체를 만들 수 있습니다.
# 리스트 연결
list1 = [1, 2, 3]
list2 = [4, 5, 6]
result = list1 + list2
print(result) # [1, 2, 3, 4, 5, 6]
# 튜플 연결
tuple1 = (1, 2, 3)
tuple2 = (4, 5, 6)
result = tuple1 + tuple2
print(result) # (1, 2, 3, 4, 5, 6)
# 문자열 연결
str1 = 'Hello, '
str2 = 'World!'
result = str1 + str2
print(result) # Hello, World!
주의: range는 + 연산자로 연결할 수 없습니다.
r1 = range(0, 5)
r2 = range(5, 10)
# result = r1 + r2 # TypeError!
# range를 연결하려면 리스트로 변환
result = list(r1) + list(r2)
print(result) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
다른 자료형은 연결 불가:
# 에러!
result = [1, 2] + (3, 4) # TypeError
result = [1, 2] + "34" # TypeError
* 연산자로 시퀀스 객체를 특정 횟수만큼 반복합니다.
# 리스트 반복
numbers = [1, 2, 3]
result = numbers * 3
print(result) # [1, 2, 3, 1, 2, 3, 1, 2, 3]
# 튜플 반복
fruits = ('apple', 'banana')
result = fruits * 2
print(result) # ('apple', 'banana', 'apple', 'banana')
# 문자열 반복
text = 'Ha'
result = text * 5
print(result) # HaHaHaHaHa
# 구분선 만들기
print('=' * 50)
# ==================================================
실용 예시:
# 초기값으로 채워진 리스트 생성
zeros = [0] * 10
print(zeros) # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# 별 찍기
for i in range(1, 6):
print('*' * i)
# *
# **
# ***
# ****
# *****
len() 함수로 시퀀스 객체의 요소 개수를 구할 수 있습니다.
# 리스트
numbers = [1, 2, 3, 4, 5]
print(len(numbers)) # 5
# 튜플
fruits = ('apple', 'banana', 'cherry')
print(len(fruits)) # 3
# 문자열 (공백 포함!)
text = 'Hello, World!'
print(len(text)) # 13 (공백, 쉼표, 느낌표 포함)
# range
r = range(1, 11)
print(len(r)) # 10
문자열의 길이는 공백까지 포함합니다.
text = '안녕하세요'
print(len(text)) # 5
text_with_spaces = '안녕 하세요'
print(len(text_with_spaces)) # 6 (공백 포함)
인덱스(Index)는 시퀀스 내 요소의 위치 값을 의미합니다.
파이썬의 인덱스는 0부터 시작합니다.
fruits = ['apple', 'banana', 'cherry', 'date']
# [0] [1] [2] [3]
print(fruits[0]) # apple
print(fruits[1]) # banana
print(fruits[2]) # cherry
print(fruits[3]) # date
시각화:
인덱스: 0 1 2 3
값: 'apple' 'banana' 'cherry' 'date'
음수 인덱스는 뒤에서부터 요소를 추출합니다. -1은 마지막 요소입니다.
fruits = ['apple', 'banana', 'cherry', 'date']
# [-4] [-3] [-2] [-1]
print(fruits[-1]) # date (마지막)
print(fruits[-2]) # cherry (뒤에서 두 번째)
print(fruits[-3]) # banana (뒤에서 세 번째)
print(fruits[-4]) # apple (뒤에서 네 번째 = 첫 번째)
시각화:
양수 인덱스: 0 1 2 3
값: 'apple' 'banana' 'cherry' 'date'
음수 인덱스: -4 -3 -2 -1
문자열도 시퀀스이므로 인덱싱이 가능합니다.
text = 'Python'
# [0][1][2][3][4][5]
print(text[0]) # P
print(text[1]) # y
print(text[-1]) # n (마지막)
print(text[-2]) # o (뒤에서 두 번째)
인덱스는 항상 (요소 개수 - 1)까지만 존재합니다.
fruits = ['apple', 'banana', 'cherry']
# 인덱스: 0, 1, 2 (총 3개이므로 최대 인덱스는 2)
print(fruits[2]) # cherry ✅
# print(fruits[3]) # IndexError: list index out of range ❌
# 안전한 인덱스 범위 확인
if 3 < len(fruits):
print(fruits[3])
else:
print('인덱스가 범위를 벗어났습니다')
리스트는 []로 요소에 접근한 뒤 =로 값을 할당하여 수정할 수 있습니다.
fruits = ['apple', 'banana', 'cherry']
# 요소 수정
fruits[1] = 'orange'
print(fruits) # ['apple', 'orange', 'cherry']
# 음수 인덱스로도 수정 가능
fruits[-1] = 'grape'
print(fruits) # ['apple', 'orange', 'grape']
튜플과 range는 값을 변경할 수 없습니다.
# 튜플 - 수정 불가
fruits = ('apple', 'banana', 'cherry')
# fruits[1] = 'orange' # TypeError: 'tuple' object does not support item assignment
# range - 수정 불가
r = range(1, 6)
# r[0] = 10 # TypeError: 'range' object does not support item assignment
문자열도 불변(immutable) 자료형이므로 수정할 수 없습니다.
text = 'Python'
# text[0] = 'J' # TypeError: 'str' object does not support item assignment
# 문자열을 변경하려면 새로 만들어야 함
text = 'Jython'
print(text) # Jython
del 키워드로 리스트의 요소를 삭제할 수 있습니다.
fruits = ['apple', 'banana', 'cherry', 'date']
# 인덱스로 삭제
del fruits[1] # 'banana' 삭제
print(fruits) # ['apple', 'cherry', 'date']
# 음수 인덱스로도 삭제 가능
del fruits[-1] # 'date' 삭제
print(fruits) # ['apple', 'cherry']
주의: 튜플, range, 문자열은 삭제 불가
fruits = ('apple', 'banana', 'cherry')
# del fruits[1] # TypeError
슬라이싱은 시퀀스 객체의 일부를 잘라내는 기능입니다.
시퀀스[시작:끝]
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 인덱스 0부터 5 전까지 (0, 1, 2, 3, 4)
print(numbers[0:5]) # [0, 1, 2, 3, 4]
# 인덱스 2부터 7 전까지 (2, 3, 4, 5, 6)
print(numbers[2:7]) # [2, 3, 4, 5, 6]
중요: 끝 인덱스는 포함되지 않으므로, 처음부터 끝까지 가져오려면 [0:끝 인덱스 + 1]을 사용해야 합니다.
fruits = ['apple', 'banana', 'cherry']
# 전체 가져오기 (0부터 3 전까지)
print(fruits[0:3]) # ['apple', 'banana', 'cherry']
print(fruits[0:len(fruits)]) # ['apple', 'banana', 'cherry']
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 중간 부분 추출
print(numbers[3:7]) # [3, 4, 5, 6]
print(numbers[2:5]) # [2, 3, 4]
인덱스를 생략하면 자동으로 처음 또는 끝으로 설정됩니다.
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 시작 생략 (처음부터)
print(numbers[:5]) # [0, 1, 2, 3, 4]
# 끝 생략 (끝까지)
print(numbers[5:]) # [5, 6, 7, 8, 9]
# 둘 다 생략 (전체 복사)
print(numbers[:]) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
| 표기 | 의미 |
|---|---|
[:5] | 처음부터 인덱스 4까지 |
[5:] | 인덱스 5부터 끝까지 |
[:] | 전체 (복사) |
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 뒤에서 5개 요소
print(numbers[-5:]) # [5, 6, 7, 8, 9]
# 처음부터 뒤에서 3번째 전까지
print(numbers[:-3]) # [0, 1, 2, 3, 4, 5, 6]
# 뒤에서 7번째부터 뒤에서 2번째 전까지
print(numbers[-7:-2]) # [3, 4, 5, 6, 7]
세 번째 숫자로 증가폭(step)을 지정할 수 있습니다.
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 2칸씩 증가 (짝수 인덱스만)
print(numbers[0:10:2]) # [0, 2, 4, 6, 8]
# 3칸씩 증가
print(numbers[0:10:3]) # [0, 3, 6, 9]
# 처음부터 끝까지 2칸씩
print(numbers[::2]) # [0, 2, 4, 6, 8]
# 홀수 인덱스만
print(numbers[1::2]) # [1, 3, 5, 7, 9]
증가폭을 음수로 지정하면 역순으로 추출합니다.
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 전체 역순
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
# 뒤에서부터 2칸씩
print(numbers[::-2]) # [9, 7, 5, 3, 1]
# 문자열 역순
text = 'Python'
print(text[::-1]) # nohtyP
문자열도 시퀀스이므로 슬라이싱이 가능합니다.
text = 'Hello, Python!'
print(text[0:5]) # Hello
print(text[7:13]) # Python
print(text[7:-1]) # Python
print(text[:5]) # Hello
print(text[7:]) # Python!
print(text[::2]) # Hlo yhn
print(text[::-1]) # !nohtyP ,olleH
리스트는 슬라이싱한 범위에 새로운 값을 할당할 수 있습니다.
numbers = [0, 1, 2, 3, 4, 5]
# 인덱스 2부터 4 전까지를 [10, 11]로 교체
numbers[2:4] = [10, 11]
print(numbers) # [0, 1, 10, 11, 4, 5]
numbers = [0, 1, 2, 3, 4, 5]
# 2개를 3개로 교체
numbers[2:4] = [10, 11, 12]
print(numbers) # [0, 1, 10, 11, 12, 4, 5]
# 3개를 1개로 교체
numbers[2:5] = [20]
print(numbers) # [0, 1, 20, 5]
빈 슬라이스에 할당하면 삽입 효과가 됩니다.
numbers = [0, 1, 2, 3, 4]
# 인덱스 2 위치에 삽입
numbers[2:2] = [10, 11]
print(numbers) # [0, 1, 10, 11, 2, 3, 4]
빈 리스트를 할당하면 삭제 효과가 됩니다.
numbers = [0, 1, 2, 3, 4, 5]
# 인덱스 2부터 4 전까지 삭제
numbers[2:4] = []
print(numbers) # [0, 1, 4, 5]
또는 del을 사용:
numbers = [0, 1, 2, 3, 4, 5]
del numbers[2:4]
print(numbers) # [0, 1, 4, 5]
numbers = [0, 1, 2, 3, 4, 5]
# 슬라이싱: 새 리스트 반환 (원본 유지)
result = numbers[2:4]
print(result) # [2, 3]
print(numbers) # [0, 1, 2, 3, 4, 5] (원본 유지)
# del: 원본 리스트 변경
del numbers[2:4]
print(numbers) # [0, 1, 4, 5] (원본 변경됨)
핵심: