[+복습(1)] 3. 프로그래밍과 데이터 中 자료형분류와 가변성
by 노실언니[복습위치]
▶ 프로그래밍과 데이터-Python programming and data 中 자료형들 & 자료형의 가변성
처음에 int, float, bool, str type 그리고 그들의 형변환 conversion만 배웠고
나중에 list, tuple, dict, set type 배우면서 conversion은 간단하게 넘어갔는데
위 type object에 관련된 function, method 배울 땐 뇌가 약간 과부하오더니
mutable/immutable 배우는 구간에서 뇌정지가 왔다.
공부량으로 치면 function, method에서 숙지해야할 양이 더 많은데 mutable/immutable에서 뇌정지가 온 이유는
듣긴 들었는데 뭔말인가, 지금 내 수준으론 이해 못 할 영역을 핥고가는 느낌이어서 찝찝해서이다.
새로 배운 type들을 익히는 것, 그 object에 관련한 function, method를 익히는 것도 신경쓸거지만,
위의 것들을 익히기 전에, 자료형 분류와 가변성에 대해서 간단히 정리를 하기로 했다.
뇌용량최적화의 느낌으로!
도식화한 이미지는 ⓒ 2021 no-silver. all rights reserved. copy가능, 수정가능, 출처표시만 부탁드려요 :)
1. 자료형 분류하기 : Data type categorization
[분류기준1 : 요소갯수] 해당 자료형의 요소가 한 개여야만 하는지 혹은, 요소가 여러 개도 가능하고 또 요소별 자료형도 있는지
[분류기준2 : 가변성] 변수가 가리키는 주소는 불변인 채, 값만 변경하는 것이 가능한지
(가변성에 대한 정의가 나에게 모호함, 사실 잘 모르겠음★)
[분류기준1 : 요소갯수 factor]
해당 자료형의 요소가 한 개여야만 하는지 혹은, 요소가 여러 개도 가능하고 또 요소별 자료형도 있는지
[remark]
- float → int 형변환시, 반올림이 아닌 소숫점이하 버림(내림)을 한다.
- type 표기방식 예시를 보면, 어느 하나 똑같은 모양새가 없다. 1 1.0 True "1" [1] (1) {1:1} {1} 당연한거지만 놀라움
- string(문자열)은 'str' "str" '''str''' """str""" 여러 방식으로 표기한다.
- 위 기준을 알면 형변환은 자세하게 파고들어서 외울 게 아니라 common sense approach, 상식적으로 처리가 가능하다.
- 요소를 많이 담을 수 있는 자료형은 수많은 요소 중 특정 요소만을 어떻게 불러올 수 있는지가 궁금했다.
특정 요소만을 부를 수 있으려면, 각 요소들은 유일한 지표를 가져야 한다. (사람으로 치면, 전세계 유일한 주민등록번호같은 것)
string list tuple → 순차(0~) 혹은 역순(-1~)으로 자동생성되는 정수형 인덱스
dict → 개발자가 직접 지정할 수 있는 key
set → 요소가 중복되지않음으로 요소 그 자체가 유일한 지표
[분류기준2 : 가변성 mutable]
변수가 가리키는 주소는 불변인 채, 값만 변경하는 것이 가능한지
정말ㅠㅠ 가변성에 대한 정의는 나에게 모호하다.
좀 더 파보려니 address도 무슨 heap영역이 있다하고 다른 뭐 어쩌구.. pass by value, call by reference, call by assignment ?
파지 않으니 모호하고, 파려니 조금 파가지고는 명확하게 될 것 같지 않다.
나는 class, object에 대한 개념도 정확치않고, 파이썬 초급핥는중이고,
어차피 중고급으로 넘어가면서 찬찬히 배울텐데.. 자바배울때 또 배울거같은데..
그래서, 많이 파지말고 모호한 선에서 최대한 이해해보자가 현 복습목표다. 아마 다 아시는 분께는 우습겠지요ㅠㅠ
[변수→메모리주소id(a)와 연결→주소id(a)에 값(객체)들어있음]의 상황에서,
- 모두 다 : 변수→[메모리주소id(a)의 변경]으로 전체 값(객체)를 바꿀 수 있음
- Mutable : 변수→메모리주소id(a)고정→일부 값(객체)변경이 가능
- Immutable : 변수→메모리주소id(a)고정→일부 값(객체)변경 불가능
[Remark] 날 힘들게 한 의문(모호함)과 해결
int, float, bool의 경우, a = 1 → a = 2 으로 바꿀 수 있었고,
str, tuple의 경우, str_a = "123" → str_a[0]=a 은 바꿀 수 없었기때문에,
왜 이 두 부류를 다 Immutable(불변성)에 넣어야하나? 특히 int float bool은 에러도 안 나고 잘 바뀌던데?
이런 의문이 있었다.
고민과 써치를 한 후,
Immutable이 말하는 불변성은, 무조건 일부값변경의 상황에서만 나오는 단어이고,
일부 값 변경시 에러가 나거나, 함수를 사용해서 전체값 변경메커니즘(메모리주소id(A)의 변경)으로 바꿀 수 있구나.
Mutable은 일부 값 변경시 변경된 값이 들어가는 주소는 바뀌더라도, 변수가 가리키는 주소는 변하지않는구나.
라고 깨달았다.
★ 이를 찾는 과정에서, call by reference/value/assignment 를 알게 되었다가
mutable = call by reference & immutable = call by value ? 이렇게 '착각'을 해버려서 또 오래 헷갈렸음.
전혀 다르다고 보면 되겠다.
immutable type이어도 call by reference가능하나 일부요소값 변경이 불가할 뿐! 이고,
mutable type이어도 특정 코드를 작성하면 call by value할 수 있다.
걍 다르다. 그래서 python은 call by assignment라고 부르나? 그치만, 안 배워서 모르겠음 ㅜ ㅜ
mutable/immutable과 call by ■는 어떻게 다른건지 내가 아는 선에서 가능한 명확하게 구분해보았다.
2. Declaring, Alias/Copy, Changing value
* not exact, just a means of understanding for newbie(me)
① 변수선언&객체생성
1. 객체생성
→ 2. 메모리공간에 객체담음
→ 3. 변수가 해당 객체가 들어있는 메모리공간 or 시작점 주소를 가리킴
n factor type의 경우, 변수가 시작점의 주소를 가리키고-현 object가 다음 object의 주소를 연쇄적으로 가리킴
[remark]
- [1 factor type] int, float, bool → 메모리 공간 1칸
변수variable는 값이 들어간 해당 칸의 주소id(a)를 가리킴
- [n factor type] string list tuple dict set ... → 메모리 공간 1(시작)+n칸
★변수variable는 사용자가 입력한 값이 없는 출발주소id(a)를 가리킴★ → mutable이 mutable인 이유임
id(a) ≠ id(a[0]) : 변수가 가리키는 칸과 ↔ 사용자가 입력한 여러 요소값들이 시작되는 메모리 칸이 다르다.
② 객체값 변경 → 객체전체/일부변경여부 & 가변성여부
- [객체전체 변경] : 값(객체전체)를 새로운 메모리주소에 담고, 변수는 그 새로운 메모리주소값을 가리킨다.
- [객체일부 변경] : 가변성(mutable)여부에 따라 결과가 달라진다.
ㄴ mutable +whole object changed : variable → 새로운 주소(새로운 값)
ㄴ mutable +some parts of object changed → 값을 변경한 영역의 주소는 변하나, 변수가 가리키는 주소 불변 like call by reference
ㄴ immutable + whole object changed : variable → 새로운 주소(새로운 값)
ㄴ immutable +some parts of object changed→[TypeError:'this type'object does not support item assignment]
[Remark]
- 전체든 일부든, 값을 바꾸면 무조건 새로운 값은 새로운 메모리에 들어온다. 기존 메모리 새로운 값 overwrite X
- ★ 일부요소값만 변경하는 경우만, 가변성여부 mutable에 따라 기전이 달라진다. → 나를 명확하게 해준 지점
mutable : 일부요소값만 변경하는 것 가능
immutable : 오류가 뜨므로, 정 바꾸고 싶다면 함수를 써서 whole change방식으로 돌아돌아 바꿔줘야함
- 전체/일부 변경에 따라 달라지는 이! <값변경 매커니즘>을 잘 이해해둬야
a=val1 b=a b=val2 에 대한 기전도 잘 이해할 수 있다.
③ 변수의 alias 혹은 복사본 만들기 & alias의 값변경
0. [ 변수명a = 값value ] : 값을 메모리주소에 담고, 변수a는 그 메모리주소값을 가리킨다.
- [alias] : 완전 그 자체 가상현실캐릭터가 죽을 때, 현실인간도 죽는다면 alias 관계
변수가 가리키는 주소가 같다면 alias ≒ call by reference
python 자료형이 mutable/immutable이든 상관없이 a = b는 call by reference같은 방식으로 진행된다.
- [alias의 값변경] : 기존 값변경 기전과 똑같음! ★가변성여부& 전체변경/일부변경여부에 따라 방식이 달라짐
전체변경 → alias였던 변수가 다른 주소를 가리키게되면서, alias상태가 끊어짐
값도 달라 주소도 달라
일부변경 → 가변성여부에 따라 방식이 달라짐
* 우선, 일부변경은 [n factor type]string tuple/list dict set만 가능
1 factor type의 1 factor를 변경하는 것은 전체변경이니까
* ① 변수선언의 remark 中...
-[n factor type] string list tuple dict set ... 에서,
★변수variable는 값이 없는 시작칸의 주소id(a)를 가리킴★ → mutable이 mutable인 이유
id(a)≠id(a[0]) : 변수가 가리키는 칸과 값이 시작되는 칸이 다르다.
다시(위는 본 설명을 위한 배경설명), 일부변경은mutable여부에 따라서 방식이 달라진다.
- mutable : 변경된 일부 값들의 주소는 달라진다, 그러나 변수가 가리키는 시작칸의 주소id(a)=id(b)는 달라지지않는다.
따라서 alias상태가 유지되므로, 변수b를 통해 일부값을 변경하는 것은 변수a에게도 동일한 영향을 준다.
그래서, id(a) id(b) 주소불변상태로 가변형(mutable)이라는 이름을 붙임
- immutable : 에러가 뜬다. 함수를 통해야한다. 그러면 전체변경 메커니즘을 사용하게되므로 alias상태가 끊어진다.
- [copy] : 값만 똑같지, 완전 개별적인 일란성쌍둥이? 분신?같은 관계 (분신만 죽지 본체는 안 죽으니까)
값은 같으나 주소가 다름 ≒ call by value
[remark]
python에서 call by reference/value는 mutable/immutable과 일대일대응하는 개념이 아니다.
가변성여부랑 call by ■에 많이 매몰되어있으면(나),
전체/일부변경에 따라서 또 달라진다는 것을 놓쳐버리면서, 그때부터 머리터지기시작한다.
왜냐하면 immutable은 불변형, 즉 변하지않아야한다는 느낌이 강한데,
1. 가변형 : list type b[0] = "a"
2. 불변형 : str type b = "123"
3. 불변형 : int type b = 1
이거 다 문제없이 잘 변경되고, print(b)했을 때, 잘 출력되니까... 불변이라면서 왜 잘 바뀌는데..?
뭔말인가,
가변형이 대체 뭐고, call by ■는 모고, 왜 바뀌냐..하면서 머리터졌따(나)
하지만, 인간은 언제나 답을 찾는다!
이렇게 정리하면서, 명쾌해졌다.
가변성과 상관없이!
[=] a = b → 주소동일 - call by reference같은 방식으로 진행된다.
[Changing object] 가변형이든, 불변형이든, 전체든, 일부변경이든 변경한 값은 새로운 주소에 담긴다.
+ 가변성은 일부값변경과 연관있고, 그에 대한 기전을 이해하기위해서, call by ■ 를 배우는 것 뿐이지,
mutable = call by reference도 immutable = call by value이 아니다.
Coding으로 확인해볼까!
[CODE] a=b는 변수의 주소를 넘긴다. = Call by reference (가변성 상관없음)
# = : address unchanged (Call by reference)
# 1. immutable
a = 1
b = a
print(a, b) # 1 1
print(a is b) # True 주소동일
c = "ABC"
d = c
print(c, d) # ABC ABC
print(c is d) # True 주소동일
# 2. mutable
a = [1, 2, 3]
b = a
print(a, b) # [1, 2, 3] [1, 2, 3]
print(a is b) # True 주소동일
c = {1, 2, 3}
d = c
print(c, d) # {1, 2, 3} {1, 2, 3}
print(c is d) # True 주소동일
# → All True 주소동일=주소불변
# = : address unchanged (Call by reference)
[CODE] 변경한 값은 새로운 주소에 담긴다. (전체일부/가변성 상관없음)
# Changing value(object) : address changed
# 1. immutable_whole changed: int, float, string + bool, tuple, frozenset
# 가변형type의 전체값(object)변경하기
a = 1
b = a
b = 1.0
print(a, b) # 1 1.0
print(a is b) # False 변수가 가리키는 주소변함
c = "ABC"
d = c
d = "abc"
print(c, d) # ABC abc
print(c is d) # False 변수가 가리키는 주소변함
# 2. mutable_whole changed : list, set + dict, user-definded class
# 가변형type의 전체값(object)변경하기
a = [1, 2, 3]
b = a
b = [4, 5, 6]
print(a, b) # [1, 2, 3] [4, 5, 6]
print(a is b) # False 변수가 가리키는 주소변함
c = {1, 2, 3}
d = c
d = {4, 5, 6}
print(c, d) # {1, 2, 3} {4, 5, 6}
print(c is d) # False 변수가 가리키는 주소변함
# 1, 2. → All False : 전체 값 변경시, 항상 변수가 가리키는 주소가 변함
# Changing whole value(object) : address changed & no alias
# 3. mutable_some parts changed : list + set, dict, user-definded class
# 가변형type의 일부 값(object)변경하기
a = [1, 2]
print(a) # [1, 2]
print(id(a), id(a[0])) # a:2694911775616, a[0]:2694906145072
b = a # make alias
b[0] = "A" # 일부요소값만 변경
print(a, b) # [A, 2] [A, 2] both changed → = still alias
print(id(a), id(a[0])) # a:2694911775616(불변), a[0]:2694911692400(변화)
print(id(b), id(b[0])) # b:2694911775616(불변), b[0]:2694911692400(변화)
print(a == b, a[0] == b[0], a is b, a[0] is b[0]) # All True = still alias
# Changing some part of mutable type : id(a)unchanged, id(a[.])changed & still alias
[CODE] 일부 값(object)변경은 mutable/immutable에 따라 기전이 다르다.
"""
Changing only some part of value(object) : 일부 값 변경
1. immutable → error or using some function to "Changing whole value"
2. mutable → Changing like call by reference
"""
# 1. immutable : string, tuple + int, float, bool, frozenset
a = "ABC"
b = a
b[0] = "a" # TypeError: 'str' object does not support item assignment
c = (1, 2, 3)
d = c
d[0] = "a" # TypeError: 'tuple' object does not support item assignment
# Immutable → Error : TypeError: this object does not support item assignment
# immutable의 일부 값 변경은 함수사용으로 전체 값 변경으로 치환하기 전엔 불가능
# 2. mutable : list, dict + set, user-definded class
a = [1, 2, 3]
print(a)
b = a
b[0] = "A"
print(a, b) # [A, 2, 3] [A, 2, 3]
print(a is b) # True : still alias
c = {1: 'a', 2: 'b', 3: 'c'}
print(c)
d = c
d[1] = 1
print(c, d) # {1, 2, 3} {1, 2, 3}
print(c is d) # True : still alias
# mutable의 일부 값 변경은 해당 값의 주소는 변하더라도,
# 변수가 가리키는 주소값은 변하지 않으므로 still alias & call by reference
'Computer science : 컴퓨터과학 > Student story at 혼긱' 카테고리의 다른 글
4. Python 응용하기 (1) | 2021.06.17 |
---|---|
[+복습(2)] 3. 프로그래밍과 데이터 中 값 관련 함수 & 메소드 (1) | 2021.05.27 |
3. 프로그래밍과 데이터 in Python (1) | 2021.04.29 |
2. 프로그래밍 핵심개념 in Python (0) | 2021.04.19 |
컴퓨터개론 Computer basics 총정리 (0) | 2021.04.06 |
블로그의 정보
노력하는 실버티어
노실언니