훈련소에선 한 사람만 잘못해도 다함께 얼차려를 받죠. 리스트도 마찬가지입니다. 두 변수가 동일 리스트를 가리키면, 한 쪽만 바꿔도 나란히 얻어맞죠.
a = [1, 2, 3]
a[2] = 4
print(a) # [1, 2, 4]
b = (1, 2, 3)
b[2] = 4 # TypeError 발생
a = 3 # 변수 a는 객체 3을 참조
print(id(3)) # 140722435000824
print(id(a)) # 140722435000824
b = 3
print(a is b) # True
id() 함수로 확인 가능a의 식별 번호가 동일함을 확인할 수 있음is로 확인 가능리스트의 경우
list1 = [1, 2, 3, 4, 5]
# list2와 list1이 참조하는 배열은 동일함
list2 = list1
print(list1 is list2) # True
# list2의 원소값을 바꾸면, 공통으로 참조하는 리스트 객체가 수정되어 list2에서도 원소값이 바뀜
list1[2] = 5
print(list1) # [1, 2, 5, 4, 5]
print(list2) # [1, 2, 5, 4, 5]
# list2의 원소값을 바꾸면, 공통으로 참조하는 리스트 객체가 수정되어 list1에서도 원소값이 바뀜
list2[4] = -1
print(list1) # [1, 2, 5, 4, -1]
print(list2) # [1, 2, 5, 4, -1]

num1 = 3
num2 = num1
num2 += 2
print(num1, num2) # 3, 5

num2 += 2는 실제로 num2 = num2 + 2와 같습니다. 이 연산은 객체 3의 값을 변경하지 않습니다. 애초에 int형은 이뮤터블이라서 값을 변경할 수 없어요.5를 만들고, num2가 5를 참조하도록 대입하게 됩니다.num1 = 3
num2 = num1
print(num1 is num2) # True
num2 += 2
print(num1 is num2) # False
print(num1, num2) # 3, 5
num1과 num2가 참조하는 객체가 달라졌음을 확인할 수 있죠얕은 복사
list1 = [1, 2, 3, 4, 5]
# list1의 값을 복사하여 다른 객체를 만들고, list2에 대입
list2 = list1.copy()
print(list1 is list2) # False
# list2의 원소값을 바꾸어도 list1의 원소값은 바뀌지 않음
# 두 변수가 다른 객체를 참조하고 있기 때문
list1[2] = 5
print(list1) # [1, 2, 3, 4, 5]
print(list2) # [1, 2, 5, 4, 5]

list.copy() 메서드 사용 시, 원래 리스트를 복사해서 다른 객체를 만듦list1 = [[1, 2], [3, 4]]
list2 = list1.copy()
list2[1][1] = 5
print(list1) # [[1, 2], [3, 5]]
print(list2) # [[1, 2], [3, 5]]
print(list1[0] is list2[0]) # True

list1[0]은 [1, 2], list[1]은 [3, 4]를 참조한다는 사실만 복사됨list2의 바깥 리스트는 새로 생성되지만, 안쪽 리스트 ([1, 2], [3, 4])들은 원본과 같은 참조를 공유list1[0]과 list2[0]은 동일 객체를 가리킴list1[1]과 list2[1]은 동일 객체를 가리킴깊은 복사
import copy
list1 = [[1, 2], [3, 4]]
list2 = copy.deepcopy(list1)
list2[1][1] = 5
print(list1) # [[1, 2], [3, 4]]
print(list2) # [[1, 2], [3, 5]]
print(list1[0] is list2[0]) # False

list2의 안쪽 리스트 ([1, 2], [3, 4]) 역시 리스트 객체 자체가 복사됨list1[0]과 list2[0]은 다른 객체를 가리킴list1[1]과 list2[1]은 다른 객체를 가리킴copy.deepcopy()로 깊은 복사를 사용해야 함인수가 이뮤터블일 때 (튜플 등)
def add(t, value):
t = t + (value,) # 새 튜플 생성
return t
tup = (1, 2, 3)
print(add(tup, 4)) # (1, 2, 3, 4)
print(tup) # (1, 2, 3) -> 원본은 그대로
인수가 뮤터블일 때 (리스트 등)
def change(a, idx, value):
a[idx] = value # 원본 리스트 직접 수정
return a
array = [1, 2, 3, 4, 5]
print(change(array, 2, 10)) # [1, 2, 10, 4, 5]
print(array) # [1, 2, 10, 4, 5] -> 원본도 변경됨
.copy()나 copy.deepcopy()를 사용해야 함def change(a, idx, value):
a = a.copy()
a[idx] = value # 원본 리스트의 복사본 수정
return a
array = [1, 2, 3, 4, 5]
print(change(array, 2, 10)) # [1, 2, 10, 4, 5]
print(array) # [1, 2, 3, 4, 5]
a = [[0] * 3] * 2
print(a) # [[0, 0, 0], [0, 0, 0]]
a[1][1] = 3
print(a) # [[0, 3, 0], [0, 3, 0]]
print(a[0] is a[1]) # True
a[1][1] 외 a[0][1]도 바뀐 것을 볼 수 있음a[0], a[1]가 동일 객체를 참조하기 때문a = [[0] * 3 for _ in range(2)]
print(a) # [[0, 0, 0], [0, 0, 0]]
a[1][1] = 3
print(a) # [[0, 0, 0], [0, 3, 0]]
print(a[0] is a[1]) # False
a[0]과 a[1]이 다른 객체를 참조*가 아니라 for문을 사용해야 함!!| 특징 | 뮤터블 | 이뮤터블 |
|---|---|---|
| 예시 | 리스트, 딕셔너리, 집합 | 튜플, 문자열, 정수, 실수 |
| 값 변경가능 여부 | O | X |
| 함수 내부에서 변경 시 | 기존 객체 변경 -> 원본 객체도 변경 | 새로운 객체 생성 -> 원본 객체는 그대로 |
a = [1, 2, 3, 4, 5]
print(a[2]) # 3
a = [1, 2, 3]
a.append(4)
print(a) # [1, 2, 3, 4]
a = [1, 2, 3]
print(a.pop()) # 3
print(a) # [1, 2]
a = [1, 2, 3]
print(len(a)) # 3
a = [2, 3, 4]
a.insert(0, 1) # 0 인덱스에 1 삽입
print(a) # [1, 2, 3, 4]
deque.popleft()를 쓰는 것이 빠름a = [1, 2, 3]
print(a.pop(0)) # 1
print(a) # [2, 3]
a = [1, 2, 3]
print(2 in a) # True
print(4 in a) # False