일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 알고리즘
- A태그
- 내일배움캠프
- AI 5기
- position
- Level1
- 함수성능평가
- googlesheet
- with\
- 우선순위
- Display
- vscode
- googleappscript
- cte
- 프로그래머스
- itertools
- target
- 함수실행시간
- 가상환경
- gitignore
- onClick
- WIL
- venv
- sql
- Iterator
- iterable
- AI
- python
- time()
- git #github #내일배움캠프
- Today
- Total
05의 개발 계발
[TIL] 230331 [Python] 객체의 immutable(불변) 과 mutable(가변) 본문
TIL 학습목표
- immutable 과 mutable 의 차이점을 이해한다.
- 객체의 Type 에 따라 immutable(불변) 과 mutable(가변) 을 구분 할 수 있다.
- immutable 과 mutable 의 차이를 활용해 코딩에 적용하는 예를 안다.
1) 문제점 (Problem)
for stage, monsters in stages.items():
# monsters 안에 데이터가 아무것도 남지 않을 때 까지 무한하게 반복해라!
while monsters:
for monster in monsters:
if monster.current_hp <= 0:
monsters.remove(monster)
위 코드를 작성 하였더니, 아래와 같이 경고문(warning)이 나왔다.
위 경고문은 for 문에서 mutable(가변) 인 list 가 수정이 일어나면 문제가 생길 수 있으니, 복사를 해서 사용하라는 권고문(consider)이다.
코드를 아래와 같이 ' [::] 깊은 복사 ' 를 이용해 list를 immutable(불변)으로 만들어 문제가 발생할 가능성을 배제해 주었다.
for stage, monsters in stages.items():
# monsters 안에 데이터가 아무것도 남지 않을 때 까지 무한하게 반복해라!
while monsters:
for monster in monsters[::]:
if monster.current_hp <= 0:
monsters.remove(monster)
위 과정을 살펴보며 반복문을 활용하는데에 있어 immutable(불변) 과 mutable(가변) 을 구분 할 수 있어야함을 느끼고 학습을 진행하였다.
이를 정리하며, 데이터 type에 따라 immutable(불변) 과 mutable(가변) 을 구분해보자.
2) 학습내용
학습한 내용을 정리하도록 하자. 참고자료
▶용어 정리
표준용어 | 한글용어 | 설명 | 예시 |
immutable | 불변성 | 깊은복사를 하며, 복사 시 독립적인 주소를 가진다. 즉, 복사한 객체의 변화에 원본 객체는 독립적이다. |
str , int , float , bool ... |
mutable | 가변성 | 얕은복사를 하며, 복사 시 하나의 주소를 공유한다. 즉, 복사한 객체의 변화를 원본 객체도 공유한다. | dict , list , set |
deep copy | 깊은 복사 | 값 자체를 복사해 새로운 독립적인 객체를 만든다. | [:] , [::] , copy.deepcopy() |
shallow copy | 얕은 복사 | 값이 들어있는 id를 참조해 의존적인 객체를 만든다. | = , copy() , copy.copy() |
* 깊은 복사와 얕은 복사는 참고자료를 통해 이해하도록 하자.
▼ immutable한 데이터타입은 복사한 객체 (a_) 의 변화 (+2) 에 원본 객체 (a) 가 영향을 받지 않는다.
# immutable한 int
a=10
a_=a #a를 깊은 복사한 a_
a_+=2
print(a) # 결과 a = 10
print(a_) # 결과 a_= 12
▼ mutable한 데이터타입은 복사한 객체 (b_) 의 변화 (append 3) 에 원본 객체 (b) 가 영향을 받는다.
# mutable한 list
b=[1,2]
b_=b #b를 얕은 복사한 b_
b_.append(3)
print(b) #결과 [1,2,3]
print(b_) #결과 [1,2,3]
▶객체 구분 | 참고자료
▶Python의 데이터 보관방식 | 참고자료
j = 1
i = j
i += 1
print(id(1)) # 2631976747248 | 1의 id
print(id(j)) # 2631976747248 | 1의 id를 참조
print(id(i)) # 2631976747280 | 2의 id를 참조
print(id(2)) # 2631976747280 | 2의 id
print(id(3)) # 2631976747324 | 3의 id
print(id(3)) # 2631976747324 | 3의 id
위 코드에서 확인 할 수 있듯이, python은 객체를 생성하지 않은 값("3")도 임의로 id를 주어 저장 하고 있다.
그리고 객체를 선언하는 순간 저장해둔 값의 id를 참조하는 형식으로 구동하고 있다.
3) 시사점
[:]을 이용한 깊은 복사 시 주의해야할 점
print("\nmutable한 list")
b = [1, 2]
b_ = b # b를 얕은 복사한 b_
b_.append(3)
print(b) # 결과 [1,2,3]
print(b_) # 결과 [1,2,3]
print("\n요소가 immutable한 list[:]")
b = [1, 2]
b_ = b[:] # b를 깊은 복사한 b_
b_.append(3)
print(b) # 결과 [1,2]
print(b_) # 결과 [1,2,3]
print("\n요소의 내부는 mutable한 list[:]")
b = [[1, 2]]
b_ = b[:] # b를 깊은 복사한 b_
b_.append(3)
b_[0].append(3)
print(b) # 결과 [[1, 2, 3]]
print(b_) # 결과 [[1, 2, 3], 3]
*참고: [:] 대신 [::]를 사용해도 결과는 같게 나왔다.
위 코드에서 [:] 슬라이싱을 사용해 리스트를 추가 참조하여, mutable한 list를 immutable한 효과를 주었다.
하지만 list를 요소로 가지는 list의 경우, 요소인 list는 상위 list의 immutable함과는 별개로 mutable함을 보였다.
또한 [:] 대신 [::]를 사용해도 결과는 같았다.
즉, [:]를 사용 시, mutable한 요소를 가지고 있는 list일 경우 문제가 발생할 수 있다.
따라서 [:]는 권장되지 않는 방법이다. 대신 copy.deepcopy() 를 이용하도록 하자.
4) 알게 된 점(Learnd)
C언어에서의 포인터와는 조금 다른 python에서의 변수 참조 방법을 생각해보는 기회가 되었다.
또한 [:]를 이용한 깊은 복사와, 그 단점을 알 수 있었다.
추가로 [:] 와 [::] 의 차이점을 알아보려 했으나 정보가 부족하였다. 다음에 알게된다면 추가 포스팅을 하도록 하자.
→ 230403 알게되었다. 간략히 슬라이싱에 대해 답변해준 GPT 의 응답을 첨부한다.
즉, [:] 와 [::] 는 모두 슬라이싱(slicing)을 통해 시퀀스를 깊은 복사(deep copy)하는 방법이다.
차이점은 [::] 는step 이라는 인자를 받아 시퀀스 생성 시 부분 선택이 가능하다.
'TIL' 카테고리의 다른 글
[TIL] 230404 [Python] dictionary 의 key 인식 (1) | 2023.04.04 |
---|---|
[TIL] 230403 [Python] 배열 뒤집기 _feat( [::] 슬라이싱) (0) | 2023.04.03 |
[TIL] 230330 [VScode] 단축키 설정하기 - 터미널에서 python파일 실행 (2) | 2023.03.30 |
[TIL] 230329 [Python] threading 모듈, Timer 사용 (0) | 2023.03.30 |
[TIL] 230328 [Python] Class의 사용목적 과 list 응용 (0) | 2023.03.28 |