본문 바로가기
개발노트/python study

[스꿈스터디] Python - 할당, 얕은복사, 깊은복사

by lovvepearl 2022. 5. 23.

1. 할당

왼쪽 변수에 오른쪽 값을 대입해주는 것

변수는 할당된 값의 메모리 주소와 같은 주소값을 가진다.

my_list = [1,2,3]
a = my_list
assert id(my_list) == id(a)
# True

 

2. 얕은복사(shallow-copy)

새로운 객체를 생성하는 것

객체 내부의 아이템은 원본과 동일한 주소값을 가짐으로

껍데기만 새롭게 교체되는 것이라고 볼 수 있다.

my_list2 = [[1],[2],[3]]
shallow_copy = my_list2.copy()

assert id(my_list2) != id(shallow_copy)
# True

shallow_copy.append([4])
print(my_list2) # [[1],[2],[3]]
print(shallow_copy) # [[1],[2],[3],[4]]

위와 같이 새롭게 생성된 리스트 객체에 값을 append하면

리스트 객체 주소값이 다르기 때문에 원본에는 영향을 주지 않는다.

 

하지만 아래와 같이 리스트 객체 내부의 아이템은 원본과 동일하게

복사되기 때문에 복사본의 아이템의 값을 변경하면 원본의 주소값과 같음으로

원본에도 변경된 값이 동일하게 적용된다.

my_list2 = [[1],[2],[3]]
shallow_copy = my_list2.copy()

assert id(shallow_copy[0]) == id(my_list2[0])
# True

shallow_copy[0].append(4)
print(my_list2) # [[1,4],[2],[3]]
print(shallow_copy) # [[1,4],[2],[3]]

 

3. 깊은복사

말그대로 객체와 그 안의 아이템까지 전부 새롭게 만드는 것

deepcopy 모듈은 재귀함수 형태임으로 반복적으로 내부로 들어가면서 모든 아이템을 복사한다. 

그렇기 때문에 아래와 같이 리스트 객체 내부의 아이템의 주소값도 다르다.

my_list3 = [[1],[2],[3]]
from copy import deepcopy
deep_copy = deepcopy(my_list3)

assert id(my_list3) != id(deep_copy)
assert id(my_list3[0]) != id(deep_copy[0])
# True

 

4. literal VS iterable

literal(리터럴) : 할당하지 않은 값. 재사용하지 못함.

iterable(이터러블) : 반복할 수 있는 객체.

예) list, Queryset 등 for문 안에서 정상적으로 돌아가는 것들

 

5. 클래스 내부에서의 객체 할당

my_list 라는 리스트 객체가 클래스 내부에 정의되어 있고

a_lists라는 리스트 내부에 클래스 객체를 할당하면

할당된 각각의 클래스 객체 내부의 my_list는 동일한 주소값을 가짐으로

같은 주소값을 가진 객체에서 값을 변경하면 나머지 객체들도 모두 수정된다. 

 

어떻게하면 주소값이 다른 my_list를 정의할 수 있을까?

class A:
	def __init__(self):
    	self.my_list = []

위와 같이 생성자 함수 내부에서 바인딩되면

클래스 외부에서 호출할때마다 참조값이 다른 my_list가 생성된다.