초보 개발자

2강 수정 가능한 객체와 수정 불가능한 객체 본문

Python/윤성우 열혈 파이썬

2강 수정 가능한 객체와 수정 불가능한 객체

taehyeki 2021. 12. 15. 13:50

수정 가능학 객체를 mutable이라고 하고 (리스트, 딕셔너리와 같이 수정이 가능한 것)

수정 불가능한 객체를 immutable이라고 한다. (튜플과 같이 수정이 불가능한 것)

r = [1,2]
id(r) # 리스트의 주소 정보 확인
ex ) 51637384
r += [3,4] # 리스트에 값을 추가
r
[1,2,3,4] # 잘 추가가 됨
id(r) #리스트의 주소가 바뀌지 않았음을 확인
51637384

튜플에 저장된 값을 수정하게 되면 다음 예에서 보이듯이 새로운 튜플이 만들어 진다.

t = (1,2)
id(t) # 튜플의 주소 정보 확인
ex ) 58040192
t += [3,4] # 튜플에 값을 추가 , 이때 새로운 튜플이 만들어 진다. 
t
(1,2,3,4) # 잘 추가가 됨
id(t) #t에 저장된 튜플이 바뀌었음을 확인
53173968

수정 불가능한 객체를 대상으로 수정을 요구하는 연산을 했을 때에 새로운 객체를 생성한다.

기존의 객체에다가는 추가가 불가능(튜플이기에)  (1,2,3,4)를 담고있는 새로운 튜플을 만든다. 

그리고 그 t라는 변수가 이 만들어진 튜플을 참조하도록 만든다. 따라서 기존의 (1,2) 튜플은 레퍼런스 카운터가 0이되므로 소멸대상이 된다.

 

def add_last(m,n):
    m += n # m에 n의 내용을 추가한다.
r = [1 , 2]
add_last(r, [3,4])
r
[1,2,3,4]

첫 줄에 [1 , 2] 리스트가 생성이 되고 r이 참조를 한다, 이 후에 add_last의 인자에 넣었을 경우에

레퍼런스 카운트는 2가된다. 왜냐하면 m또한 리스트를 참조를 하고 있기 때문 이 경우 [1,2]의 메모리에 r과 m이 참조를 함으로 n을 더했을 경우에 위에서 설명한 것과 마찬가지로 주소는 같다. 따라서 r을 출력하면 [1,2,3,4]가 출력이 된다.

 

하지만 튜플의 경우에는

t = (1 , 3)
add_last(t, (5,7))
t
(1,3)

인자로 t가들어가서 m또한 (1,3)을 참조한다 그리고 (1,3) +(5,7)이 실행이 되고 

변경이 되지 않아 새로운 튜플이 새로운 메모리에 생성이 된다. 그리고 m은 그 새로운 튜플을 참조하게 된다. 따라서

기존의 t는 변함이 없는 상태여서 (1,3)을 호출하게 된다. 즉 t가 참조하는 객체와 m이 참조하는 객체는 완전히 별개 된다.

 

def add_tuple(t1,t2):
    t1 += t2 # += 결과로 만들어진 새로운 튜플이 t1에 저장된다.
    return t1 # 새로만들어진 튜플을 반환
tp = (1,3)
tp = add_tuple(tp,(5,7))
tp
(1,3,5,7)

이렇게 해주면 tp가 1,3이 아닌 1,3,5,7,을 참조하게 되는데 이건 return t1값을 tp가 다시 참조하기 때문이다.

즉 새로 만들어진 튜플을 다시 참조하는 것이다.

 

def min_max(d):
    d.sort()
    print(d[0], d[-1], sep = ",")


l = [3,1,5,4]
min_max(l)
1,5
l
[1,3,4,5] # 원본의 저장 순서가 변경되었다.

min_max에 [3,1,5,4]가 인자로 들어오면 d역시 이것을 참조하기 때문에 d의 sort함수를 사용해버리면 원본이 바뀌어 버린다. 따라서 l을 다시 출력해보면 원본이 바뀐 것을 알 수 있다.

 

이걸 해결하기 위해서는 복제본을 사용하면 된다.

def min_max(d):
	d = list(d) #d의 내용이 담긴 새로운 리스트 생성해주고
    d.sort() # 원본이 아닌 복사본을 정렬한다.
    print(d[0], d[-1], sep = ",")


l = [3,1,5,4]
min_max(l)
1,5
l
[3,1,5,4] # 원본이 수정되지 않았다.