리스트

0. 리스트의 기본 개념

여러개의 값을 하나의 변수에 순서대로 저장하는 자료형이다.

컨테이너 자료형이며, 데이터 전처리 과정에서 핵심적으로 사용된다.

# 1. 리스트 생성
my_list = [1, 2, 3, 4, 5]

# 2. list()함수 사용
chars = list('hello')

# 3. 리스트의 기본 구조 츨력
print(my_list)  # 출력: [1, 2, 3, 4, 5]

print(chars)  # 출력: ['h', 'e', 'l', 'l', 'o']

핵심 키워드

• 저장된 값에는 순서(index) 가 있다

• 여러 개의 값을 저장할 수 있다

• 서로 다른 자료형을 함께 저장할 수 있다

• 생성 이후에도 내용을 변경할 수 있다.

0-1. 리스트의 변경 가능성 (Mutability)

리스트는 변경 가능한 객체로서, , 리스트가 한 번 생성된 이후에도 내부 요소를 직접 수정할 수 있다.

이는 뒤에서 설명할 얕은복사, 깊은복사, 메모리 관리와 데이터 처리 방식에서 매우 중요하다.


1. 리스트 인덱싱과 슬라이싱

인덱싱이란 리스트에서 특정 위치의 요소 하나를 선택하는 방법이다.

• 인덱스는 0부터 시작한다

• 음수 인덱스는 뒤에서부터 접근한다

 

사용 예시

cities = ["Seoul", "Busan", "Incheon"]
print(cities[0]) 	# Seoul
print(cities[-1])	# Incheon

 

슬라이싱 = 원하는 부분을 자르는 것.

 

 

리스트[start : stop : step]

• start: 슬라이싱을 시작할 인덱스 (포함).

• stop: 슬라이싱을 종료할 인덱스 (미포함).

• step: 요소를 건너뛰는 간격.

 

사용 예시

cities = ["Seoul", "Busan", "Incheon", "Gwangju", "Daejeon"]
sub = cities[1:4]
print(sub)

# 출력: ['Busan', 'Incheon', 'Gwangju']

 

 

2. 리스트의 메소드

파이썬은 리스트를 조작하기 위한 다양한 내장 메소드를 제공한다.

 

append / insert / extend (요소의 추가)

my_list.append(6)
my_list.insert(2, 10)
my_list.extend([7, 8, 9])

• append - 리스트에 하나의 값(요소) 을 맨 뒤에 추가

• insert - 기존 순서를 유지하면서, 지정한 위치(index) 에 값을 삽입 (이때 기존 값들은 오른쪽으로 한 칸씩 밀린다 )

• extend- 여러 개의 값을 풀어서 추가 → “리스트와 리스트를 이어 붙인다”란 개념으로 접근

remove / pop / clear (요소의 제거)

my_list.remove(3)
popped_value = my_list.pop(5)
my_list.clear()

• remove - 값을 기준으로 첫 번째로 일치하는 요소를 제거

• pop - 지정한 인덱스의 요소를 제거하고 그 요소를 반환한다. 반환 인덱스를 지정하지 않으면 마지막 요소를 제거

• clear - 모든 요소를 제거

index / count ( 요소 검색 및 개수 세기 )

my_list.index(4)
my_list.count(7)

• index - 요소의 인덱스를 반환.  특정 값이 처음 등장하는 위치를 알려준다

• count - 요소의 개수를 반환. 특정 값이 몇 번 등장하는지 세어준다

sort / reverse ( 정렬 )

my_list.sort()
my_list.reverse()

• sort - 리스트의 요소를 오름차순으로 정렬
• reverse - 리스트의 요소 순서를 반대로 뒤집는다


 

3. 리스트의 연산

리스트는 연산자를 사용할 수 있다.

list1 = [1, 2, 3]
list2 = [4, 5, 6]
result = list1 + list2
print(result)  # 출력: [1, 2, 3, 4, 5, 6]
print(list1*2) # 출력: [1, 2, 3, 1, 2, 3]

 

• + : 리스트 결합

• * : 반복 생성

 


4, 리스트 컴프리헨션

기존 for문 + 조건문 패턴을 한 줄로 표현해 간결하고 효율적인 방법으로 새로운 리스트를 생성하는 문법  이다.

[표현식 for 변수 in 반복가능객체]
[표현식 for 변수 in 반복가능객체 if 조건]

읽는 순서

  1. for x in range(...)
  2. if 조건
  3. 맨 앞의 표현식
# 일반적인 for문
result = []
for x in range(1, 6):
    result.append(x)

# 리스트 컴프리헨션
result = [x for x in range(1, 6)]

 

실행 순서 (Line by Line)

1. range(1, 6) 생성
2. 첫 값 x = 1
3. 표현식 x 실행 → 1
4. 리스트에 추가
5. 반복 종료까지 반복

5. 리스트의 반복문 활용

리스트의 각 요소에 접근하거나 처리하기 위해 반복문을 사용할 수 있다.

fruits = ['apple', 'banana', 'cherry']

for fruit in fruits:
    print(fruit, end = ' ')
    
# 출력: apple banana cherry

 

인덱스와 함께 반복할수도 있다.

# enumerate : 인덱스와 값을 함께 불러올 수 있습니다.
for index, value in enumerate(fruits):
    print(f'인덱스 {index}: {value}')

6. 중첩문

리스트 안에 또 하나의 리스트를 넣을수도 있다

matrix = [
    [1, 2],
    [3, 4],
    [5, 6]
]
for row in matrix:
    for value in row:
        print(value) # 출력: 1 2 3 4 5 6

개념적으로 보면
바깥 for문 → “행 단위 접근”
안쪽 for문 → “해당 행의 요소 접근”
리스트 컴프리헨션에서 중첩이 등장할 때도 이 순서가 그대로 유지된다.

⭐ 중첩 리스트는 항상 밖에서부터 안쪽을 천천히 까보면서 들어가야 한다. ⭐


7. 리스트의 얕은 복사, 깊은 복사

파이썬에서의 리스트는 값이 아닌 '객체' 즉, 메모리에 따로 저장되는 요소라 봐도 무방하다.

이때의 변수는 리스트가 저장된 위치를 가리키는 이름표라 생각하면 편하다.

a = [1, 2, 3] → a 안에 [1, 2, 3]이 들어있다 ❌

a는 [1, 2, 3]이 “있는 위치를 가리킨다” ⭕


그림으로 보면....
메모리 어딘가:
[1, 2, 3]  ← 실제 리스트

a ─────────▶ [1, 2, 3]

 

설명하기전 짚고 넘어가기

a = [1, 2, 3]
b = a

해당 코드는 다음과 같이 표현된다.

a ─────▶ [1, 2, 3]
b ─────▶ [1, 2, 3]

리스트는 1개이지만, 이름표가 a와 b 이다.

 

만약 여기서 append를 해 b를 바꿔보자

b.append(4)
print(a)

# 출력 [1, 2, 3, 4]

??

분명 b에 append를 사용해서 바꾸었는데 a도 바뀌였다.

왜 a도 바뀐걸까?

[1, 2, 3, 4]

이유는 a와 b모두 같은 리스트를 가르키고 있기 때문이다.

 

7-1. 얕은 복사(Shallow Copy)란?

겉에 있는 리스트만 새로 만들고 안에 들어 있는 리스트는 같이 쓰는 복사

• 리스트 껍데기는 새 것

• 안에 들어 있는 객체들은 공유

original = [1, 2, [3, 4]]
shallow = original[:]

메모리의 관점

original ──▶ [1, 2, ──▶ [3, 4]]
shallow  ──▶ [1, 2, ──▶ [3, 4]]

겉리스트는 2개지만, 안의 리스트는 1개다.

즉...

shallow[2][0] = 'a'

print(original)
# [1, 2, ['a', 4]]

print(shallow)
# [1, 2, ['a', 4]]

겉의 리스트는 다른 리스트를 사용하지만, 속은 같은 리스트를 사용하기 때문에 변한것이다.

즉, “껍데기만 복사하고, 안에 든 객체는 같이 쓴다” 라는 의미다.

 

어떨때 발생하나?

• 슬라이싱 [:]
• list()
• copy.copy()
• list.copy()

 

❗ 주의사항 ❗

• 숫자, 문자열은 안 바뀌는 값

• 안에 또 리스트가 없음

• 1차원 리스트 → 얕은 복사 OK

 

7-2. 깊은 복사(Deep Copy) 란?

바깥 리스트, 그 안의 모든 하위 객체를 전부 새로 복사한다.

원본과 복사본이 어느 수준에서도 객체를 공유하지 않는다

즉, 객체 구조 전체를 새로 만드는것이라 볼수 있다.

import copy

original = [1, 2, [3, 4]]
deep = copy.deepcopy(original)

만약 deep의 값을 변경하면?

deep[2][0] = 'a'

print(original)
# [1, 2, [3, 4]]

print(deep)
# [1, 2, ['a', 4]]

 

겉과 속 모두 다른 리스트를 가리키고 있기때문에 개별적이라 볼수 있다.

 

7-3. 표로 보기

구분 얕은 복사 깊은 복사
바깥 객체 새로 생성 새로 생성
내부 객체 공유 전부 새로 생성
독립성 부분적 완전
중첩 리스트 위험 안전

 

7-4 어렵다면 이렇게 생각하기

안에 리스트가 있나?

없다 → 얕은 복사 OK
있다 → 깊은 복사 필요

 


8. 리스트와 메모리 관리

파이썬에서 변수는 “값을 담는 상자”가 아니라 객체를 가리키는 이름표이다

a = [1, 2, 3]
b = a

• 리스트 객체는 메모리에 하나

• a, b는 같은 주소를 참조

 

만약 리스트가 변경되면...

b.append(4)

• 리스트 객체 자체가 변경됨

• 그 객체를 참조하는 모든 변수가 영향을 받음

 

 

얕은 복사

 

  • 바깥 리스트 주소는 다름
  • 내부 리스트 주소는 같음

깊은 복사

 

  • 모든 객체가 서로 다른 주소
  • 완전 독립

 

 


 

9. 리스트의 실용 예제

중복 제거

리스트에는 같은 값이 여러 번 들어갈 수 있다. 만약 중복을 제거한 값이 필요한 경우... set을 사용한다.

수도코드로 보기

숫자가 여러 개 들어 있는 리스트를 준비한다
리스트를 set으로 변환하여 중복을 제거한다
다시 리스트로 변환한다
결과를 출력한다

 

numbers = [1, 2, 2, 3, 4, 4, 5]
unique_numbers = list(set(numbers))
print(unique_numbers)

 

실행 순서 (Line by Line)

1. numbers 리스트 생성 # [1, 2, 2, 3, 4, 4, 5]
2. set(numbers) 실행 # {(1, 2, 3, 4, 5)
3. 중복된 2,4는 하나만 남는다. (순서 보장 x)
4. list(...) 실행  # [1, 2, 3, 4, 5]

 

 

컴프리헨션을 사용한 조건부 리스트

1부터 20까지 숫자 중 3의 배수만 리스트로 만들기

수도코드로 보기

1부터 20까지 숫자를 하나씩 확인한다
해당 숫자가 3으로 나누어 떨어지면
리스트에 추가한다

 

multiples_of_three = [x for x in range(1, 21) if x % 3 == 0]
print(multiples_of_three)

#출력: [3, 6, 9, 12, 15, 18]

 

실행 순서 (Line by Line)

1. range(1, 21) 생성
2. 값 x의 몫이 0이면 참(값을 반환), 0아 아니면 거짓 (다음 x 값으로)
3. 리스트 출력

 

 

2차원 리스트에서의 특정 조건의 요소 찾기

 

수도코드로 보기

각 행(row)을 하나씩 가져온다
행 안의 각 요소(item)를 하나씩 확인한다
item이 30보다 크면
결과 리스트에 추가한다

 

matrix = [
    [5, 10, 15],
    [20, 25, 30],
    [35, 40, 45]
]
result = [item for row in matrix for item in row if item > 30]
print(result)

# 출력 [35, 40, 45]

 

실행 순서 (Line by Line)

1. 첫 번째 행 검사 [5, 10, 15]
2. 두번째 행 검사 [20. 25. 30]
3 세 번째 행 검사 [35, 40, 45]  (모두 30을 초과했기 때문에 리스트에 반환)
4. 출력

10. 리스트 학습한 내용

  • 리스트의 기본 개념과 변경 가능성
  • 인덱싱과 슬라이싱의 동작 원리
  • 리스트 주요 메소드의 내부 동작 방식
  • 리스트 연산과 반복문의 결합
  • 리스트 컴프리헨션의 구조적 의미
  • 중첩 리스트와 메모리 참조 개념
  • 데이터 전처리에 활용되는 실용 패턴

튜플

0.  튜플의 기본 개념

여러 개의 값을 하나로 묶어 저장하는 자료형이다.
리스트와 매우 유사하지만, 가장 큰 차이점은 값을 변경할 수 없다는 점이다.

• 순서가 존재

• 요소의 추가, 삭제, 변경이 불가능

• 여러 데이터를 담을수 있음

• 대괄호 [ ]를 사용하여 리스트 생성

 

0-1. 튜플의 불변성

튜플은 불변(immutable) 자료형이다.

한 번 생성된 튜플은 요소의 추가, 삭제, 수정이 불가능하다.


1. 튜플의 생성법

 

기본 생성

t1 = (1, 2, 3)

t2 = 1, 2, 3

 

요소가 하나인 튜플

t3 = (1,)   # 쉼표 필수
t4 = (1)    # 튜플 아님, 정수
 

 

튜플 패킹

# () 없이 생성 (튜플패킹)
my_tuple = 1, 2, 3
print(my_tuple)        # 출력: (1, 2, 3)
print(type(my_tuple))  # 출력: <class 'tuple'>

 

함수를 이용한 생성

# tuple()함수를 사용해 생성
my_list = [1, 2, 3]
my_tuple = tuple(my_list) # 리스트를 튜플로 변환
print(my_tuple)  # 출력: (1, 2, 3)

2. 튜플 인덱싱 & 슬라이싱

튜플도 순서가 있는 자료형이므로 인덱싱과 슬라이싱이 가능하나, 다른점은 ❗수정은 불가능❗ 

fruits = ('apple', 'banana', 'cherry', 'date')

print(fruits[0])    # 출력: apple
print(fruits[2])    # 출력: cherry
print(fruits[-1])   # 출력: date (마지막 요소)
print(fruits[-2])   # 출력: cherry

 

튜플 슬라이싱

numbers = (0, 1, 2, 3, 4, 5, 6)

print(numbers[2:5])    # 출력: (2, 3, 4)
print(numbers[:3])     # 출력: (0, 1, 2)
print(numbers[4:])     # 출력: (4, 5, 6)
print(numbers[::2])    # 출력: (0, 2, 4, 6)
print(numbers[::-1])   # 출력: (6, 5, 4, 3, 2, 1, 0)

3. 튜플 메소드(Tuple Methods)

count() - 특정 요소의 개수를 반환. 특정 값이 몇 번 등장했는지

numbers = (1, 2, 2, 3, 3, 3)
print(numbers.count(2))  # 출력: 2
print(numbers.count(3))  # 출력: 3

index() - 첫 번째로 일치하는 요소의 인덱스를 반환. 특정 값이 처음 등장한 위치 확인

fruits = ('apple', 'banana', 'cherry')
print(fruits.index('banana'))  # 출력: 1

4. 튜플과 리스트의 차이점

구분 리스트 튜플
변경 가능 O X (불변성 때문)
추가/삭제 가능 X (불변성 때문)
용도 데이터 조작이 필요한 경우 변경이 불필요한 테이터
key
성격 작업용 고정데이터, 보관용
비유 메모장 인쇄된 문서

5. 튜플의 활용

딕셔너리의 키로 활용

딕셔너리의 키는 변경 불가능한 자료형만 가능하므로 튜플은 키로 사용할 수 있다.

my_dict = { (1, 2): "Point A", (3, 4): "Point B" }
print(my_dict[(1, 2)])  # 출력: Point A

 

 

함수의 복수 반환값

수도코드로 보기

함수에서 두 값을 한 번에 반환한다

 

def calc(a, b):
    return a + b, a - b

result = calc(10, 3)

# (13, 7)

 

 

변수의 패킹과 언패킹

 

패킹: 여러개의 값을 하나의 튜플로 묶는것을 의미

packed_tuple = 1, 2, 3
print(packed_tuple)  # 출력: (1, 2, 3)

 

 

 

언패킹: 튜플의 요소를 여러 개의 변수에 할당하는 것을 의미

a, b, c = packed_tuple
print(a)  # 출력: 1
print(b)  # 출력: 2
print(c)  # 출력: 3

6. 중첩 튜플(Nested Tuples)

튜플 안에 튜플을 요소로 가질 수 있습니다.

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

# 접근법
print(t[0][1])

#출력: 2

 

 

7. 튜플의 반복문 활용

튜플의 각 요소에 접근하거나 처리하기 위해 반복문을 사용할 수 있다.

fruits = ('apple', 'banana', 'cherry')

for fruit in fruits:
    print(fruit)

apple
banana
cherry

 

인덱스와 함께 반복

for index, value in enumerate(fruits):
    print(f'인덱스 {index}: {value}')
    
인덱스 0: apple
인덱스 1: banana
인덱스 2: cherry

8. 튜플의 비교와 정렬

튜플은 요소별로 비교할 수 있으며, 정렬된 시퀀스를 필요로 하는 경우에 유용하다.

# 튜플끼리의 비교
tuple1 = (1, 2, 3)
tuple2 = (1, 2, 4)

print(tuple1 < tuple2)  # 출력: True

 

튜플 안에 존재하는 리스트를 정렬 할수도 있다.

students = [('John', 'A', 15), ('Jane', 'B', 12), ('Dave', 'A', 10)]

# 나이를 기준으로 정렬
students_sorted = sorted(students, key=lambda student: student[2])
print(students_sorted)
# 출력: [('Dave', 'A', 10), ('Jane', 'B', 12), ('John', 'A', 15)]

 

9. 실용예제

두 변수의 값 교환

a = 10
b = 20

a, b = b, a  # 값 교환

print(a)  # 출력: 20
print(b)  # 출력: 10

리스트와 상호 변환

my_tuple = (1, 2, 3)
my_list = list(my_tuple)
print(my_list)  # 출력: [1, 2, 3]

my_new_tuple = tuple(my_list)
print(my_new_tuple)  # 출력: (1, 2, 3)

여러 변수에 동일한 값 할당

x = y = z = 0
print(x, y, z)  # 출력: 0 0 0

10. 튜플 학습한 내용

  • 튜플은 변경할 수 없는 자료형이다
  • 리스트와 문법은 유사하지만 용도가 다르다
  • 안전하게 데이터를 보호해야 할 때 튜플을 사용한다
  • 함수 반환값, 딕셔너리 키, 값 교환에 자주 활용된다

딕셔너리

값을 위치(index)가 아닌 키(key)와 값(value)을 한 쌍으로 저장하는 자료형

리스트나 튜플과 달리, 순서가 아니라 키를 통해 값에 접근한다.

 

 

키(key)과 값(value)의 쌍을 저정한다.

값(value)은 뭐든 될 수 있다

•숫자

•문자열

•리스트

•튜플

•딕셔너리 조차 가능

# 빈 딕셔너리 생성
empty_dict = {}

# 키-값 쌍을 가진 딕셔너리
person = {
    'name': 'Alice',
    'age': 25,
    'city': 'New York'
}

print(empty_dict)  # 출력: {}
print(person)      # 출력: {'name': 'Alice', 'age': 25, 'city': 'New York'}

⭐ 순서가 목적이 아니다. 딕셔너리는 “몇 번째냐”가 아닌 “무엇이냐”가 중요하다 ⭐


1. 딕셔너리 생성 방법

중괄호 {} 사용

# 기본적인 딕셔너리 생성
student = {
    'id': 12345,
    'name': 'John Doe',
    'grade': 'A'
}

dict()를 사용

# 키워드 인자를 사용한 생성
car = dict(brand='Ford', model='Mustang', year=1964)
print(car)  # 출력: {'brand': 'Ford', 'model': 'Mustang', 'year': 1964}

# 리스트나 튜플의 리스트를 사용한 생성
items = [('apple', 2), ('banana', 3)]
fruit_dict = dict(items)
print(fruit_dict)  # 출력: {'apple': 2, 'banana': 3}

2. 딕셔너리 요소 접근 및 변경

요소의 접근

수도코드로 보기

키를 이용해 해당 값을 가져온다

 

person = {'name': 'Alice', 'age': 25, 'city': 'New York'}

# 키를 사용하여 값에 접근
print(person["name"])

# 출력: Alice

# `get()` 메서드를 사용하여 값에 접근 (키가 없을 때 기본값 설정 가능)
print(person.get('city'))       # 출력: New York

 

값 변경

수도코드로 보기

기존 키에 새로운 값을 할당한다
person["age"] = 26

 

요소 추가&삭제

# 값의 추가
person["job"] = "Data Analyst"

# `del` 키워드를 사용하여 요소 삭제
del person['city']
print(person)  # 출력: {'name': 'Alice', 'age': 26, 'country': 'USA'}

# `pop()` 메서드를 사용하여 요소 삭제 및 값 반환
age = person.pop('age')
print(age)     # 출력: 26
print(person)  # 출력: {'name': 'Alice', 'country': 'USA'}

# 모든 요소 삭제
person.clear()
print(person)  # 출력: {}

3. 딕셔너리 메소드

keys()

모든 키를 dict_keys 객체로 반환 ( 컬럼 목록 확인 느낌 )

person = {'name': 'Alice', 'age': 25, 'city': 'New York'}
keys = person.keys()
print(keys)  # 출력: dict_keys(['name', 'age', 'city'])

 

values()

모든 값을 dict_values 객체로 반환 ( 실제 데이터들만 모아서 보기 )

person = {'name': 'Alice', 'age': 25, 'city': 'New York'}
keys = person.keys()
print(keys)  # 출력: dict_keys(['name', 'age', 'city'])

items()

딕셔너리의 모든 키-값 쌍을 튜플로 반환

 

 

items = person.items()
print(items)  # 출력: dict_items([('name', 'Alice'), ('age', 25), ('city', 'New York')])

4. 딕셔너리의 반복문 활용

4-1. 키를 통한 기본 반복

for key in person:
    print(key, person[key])

4-2. keys() 메소드 활용

for key in person.keys():
    print(key)

4-3. values() 메소드 활용

for value in person.values():
    print(value)

4-4. items() 메소드 활용

for key, value in person.items():
    print(key, value)

5. 딕셔너리의 컴프리헨션

반복문과 조건을 사용해 딕셔너리를 한 줄로 생성하는 문법

squares = {x: x**2 for x in range(1, 6)}

6. 딕셔너리와 관련된 함수들

6-1. len()

딕셔너리의 키-값 쌍의 개수를 반환

person = {'name': 'Alice', 'age': 26, 'city': 'New York', 'country': 'USA'}
print(len(person))  # 출력: 4

6-2. in 연산자

딕셔너리에 특정 키가 존재하는지 확인

print('name' in person)     # 출력: True
print('email' in person)    # 출력: False

6-3. del 키워드

딕셔너리 자체를 삭제하거나 모든 요소를 삭제

del person['country']  # 특정 키-값 쌍 삭제
del person             # 딕셔너리 전체 삭제

7. 중첩 딕셔너리

딕셔너리 안에 또 다른 딕셔너리를 저장할 수 있다.

students = {
    "Alice": {"math": 90, "eng": 85},
    "Bob": {"math": 75, "eng": 80}
}

print(students["Alice"]["math"])
# 출력: 90

8.딕셔너리의 응용

키로 사용할 수 없는 자료형

# 다음 코드는 오류를 발생시킵니다.
my_dict = { [1, 2, 3]: 'Numbers' }  # TypeError: unhashable type: 'list'

람다(lambda) 함수란?

이름 없는 간단한 함수를 의미한다.

# 같은 의미
square = lambda x: x * x           	# 람다
def square(x): return x * x        	# def


add = lambda a, b: a + b			# 람다
def add(a, b): return a + b      	# def

기능적 관점에서 보면 두 함수 모두 입력값 받아 return으로 값을 반환한다.

 

람다를 쓰는 이유는...

잠깐 쓰고 버릴 함수로 쓰기 위해서이다.


 

9. 딕셔너리와 JSON 데이터

JSON은 키-값 구조의 데이터 포맷이고, 파이썬 딕셔너리와 구조가 매우 유사하다.

import json

person = {'name': 'Alice', 'age': 25, 'city': 'New York'}

# 딕셔너리를 JSON 문자열로 변환
json_str = json.dumps(person)
print(json_str)
# 출력: {"name": "Alice", "age": 25, "city": "New York"}

(오픈/공공 데이터가 JSON 형태인 경우가 많아, 파이썬 딕셔너리 형태로 변환하여 처리하는 경우 다수)


 

10. 딕셔너리 학습한 내용

 

  • 딕셔너리는 키-값 구조의 자료형이다
  • 키를 통해 빠르게 값에 접근할 수 있다
  • 반복문과 컴프리헨션을 통해 효율적으로 처리할 수 있다
  • 중첩 구조를 통해 복잡한 데이터 표현이 가능하다
  • JSON 데이터 처리의 기본이 되는 자료형이다

[보충] Immutable / Mutable 개념 정리

1. 객체(Object)란 무엇인가?

정수, 실수, 문자열, 리스트, 튜플, 딕셔너리, 함수까지 모두 메모리 공간에 저장된것을 객체라 부른다.

즉, 값(value)과 기능(Methods)을 함께 가진 데이터 덩어리를 의미한다.

 

객체는 다음 두 가지를 반드시 가집니다.

값(Value)

주소(Address, 메모리 위치)

 

예를 들어

a = 10

이 문장은 다음 의미를 가진다.

메모리에 10이라는 값이 저장됨

변수 a는 그 값이 저장된 주소를 가리킴

 

여기서 포인트는  변수는 값을 직접 담고 있는 것이 아니라, 객체를 가리키고 있다는 점이다.


2. Immutable / Mutable의 핵심 차이

구분 정리
Immutable 바꿀 수 없음 객체 자체를 수정할 수 없음
Mutable 바꿀 수 있음 객체 자체를 수정할 수 있음

중요한 포인트는 “변수를 바꾼다”와 “객체가 바뀐다”는 전혀 다른 개념

같은 객체를 유지한 채 내용만 바꿀 수 있는가?


3. Immutable 객체 (변경 불가능)

대표적인 immutable 자료형은 다음과 같다.

 

  • int
  • float
  • bool
  • str
  • tuple
a = 10
a = a + 1

 

겉보기에는 a가 11로 바뀐 것처럼 보이지만 실제로는 다음 순서로 동작한다.

10이라는 객체 생성
a가 10을 가리킴
11이라는 새로운 객체 생성
a가 11을 가리키도록 변경

즉, 10 객체는 그대로 존재

a가 가리키는 대상만 바뀌였다.

 

s = "hello"
s[0] = "H"   # 에러 발생

# 해결책
s = "H" + s[1:]

이유:

문자열은 immutable

문자열 내부의 문자 하나도 직접 수정 불가

 

때문에 새 문자열 생성 해야 한다.


4. Mutable 객체 (변경 가능)

대표적인 mutable 자료형은 다음과 같다.

  • list
  • dict
  • set
lst = [1, 2, 3]
lst[0] = 100

print(lst) #출력: [100, 2, 3]

 

 

 

코드 동작 순서

  1. [1, 2, 3] 리스트 객체 생성
  2. lst가 해당 리스트 객체를 가리킴
  3. 리스트 내부 값 변경
  4. 객체 주소는 그대로 유지

즉, 객체는 그대로이며 내용만 변경된것이다.

 

d = {"a": 1}
d["a"] = 100

print(d) #출력: {'a': 100}

딕셔너리도 mutable이므로 내부 값 변경이 가능하다.


5. 헷갈리기 쉬운 포인트

포인트 1: 변수의 변경 ≠ 객체의 변경

a = 10
b = a
a = 20

 

  • a와 b는 처음에 같은 객체(10)를 가리킴
  • a = 20은 새 객체를 가리키는 것
  • b는 여전히 10을 가리킴

포인트 2: mutable 객체는 참조가 공유됨

a = [1, 2, 3]
b = a
b.append(4)

# 결과
a → [1, 2, 3, 4]
b → [1, 2, 3, 4]

 

 

  • a와 b가 같은 리스트 객체를 공유
  • 리스트는 mutable

6. 표로 정리해서 보기

구분 Immutable Mutable
객체 수정 불가능 가능
객체 재사용 불가능 가능
변경 방식 새 객체 생성 기존 객체 수정
대표 자료형 int, float, str, tuple list, dict, set
비유 잉크로 쓴 종이 연필로 쓴 노트

 

 

+ Recent posts