파이썬에는 복사를 편하게 하기 위해 copy 모듈에서 copy와 deepcopy 함수를 제공합니다. 이 글에서는 파이썬 copy deepcopy 차이를 알아보도록 하겠습니다.
글에서 사용할 클래스
이 글에서 실습해 볼 클래스는 아래와 같습니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp1.png)
먼저 class A는 필드 x를 가지고 있습니다. 코드에서는 integer를 넣을 거에요.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp2.png)
다음 클래스 B입니다. 필드 a는 클래스 A의 객체를 가리킵니다. 여기서 set_x를 주목해 볼 필요가 있는데요. 이 함수는 필드 a가 가리키고 있는 객체의 x 값을 바꾸는 역할을 합니다. 클래스 B의 객체가 생성되었습니다. 이 경우, 아래와 같이 메모리에 객체가 할당됩니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp8.png)
B의 필드 a에는 A(2)가 들어갈 겁니다. 이는, 필드 x의 값이 2인 객체의 참조값, 혹은 비슷한 역할을 하는 무언가입니다. 즉, 회색으로 표시된 부분은 1 depth, 노란색으로 표시된 부분은 회색 부분에서 참조 하나 더 들어갔으니 2 depth라고 할 수 있습니다.
참조값을 대입
먼저, 두 객체 a와 b가 있습니다. b = a의 의미는, b에 참조값 a를 대입한다는 의미입니다. 즉, 참조값이 복사됩니다. 흔히 우리가 알고 있는 얕은 복사의 개념입니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp3.png)
코드 1번을 보겠습니다. 필드 x의 값이 3인 객체를 하나 할당해서 a1에 대입하였습니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp9.png)
A(3)이 0x40에 있다면, 참조값은 0x40 정도 된다고 이야기 할 수 있습니다. 즉, a1은 노란색의 객체를 참조하고 있습니다. 다음에, a2에 a1의 값을 대입하였습니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp10.png)
a1과 a2는 같은 객체를 참조하고 있습니다. 만약에 a2.set_x(4)를 호출하면 어떻게 될까요? a2가 가리키고 있는 객체의 필드 x의 값이 4가 됩니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp11-1.png)
왜 그럴까요? a1과 a2는 같은 객체를 참조했기 때문입니다. 즉, 얕은 복사는 참조 값을 복사하는 것이라고 이야기 할 수 있습니다.
copy 메소드
그렇다면 copy 메소드는 어떨까요? 새로운 객체를 생성합니다. 그리고, 원본 객체의 필드 값만 복사 합니다. 뎁스가 2 이상인 경우, 얕은 복사를 하게 됩니다. 이게 무슨 이야기인지 코드 2와 3을 보겠습니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp4.png)
먼저 코드 2를 봅시다. 마찬가지로 필드 x의 값이 3인 객체 A를 생성하고, 이 객체의 참조값을 a3에 대입하였어요. 다음에 copy.copy(a3)의 리턴값을 a4에 대입하였습니다. 이 때에는 어떻게 되는가?
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp12.png)
32번째 줄이 끝난 후에 위와 같은 상황이 됩니다. 다음에, 33번째 줄의 copy 메소드가 호출된 이후 상황은 아래와 같습니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp13.png)
a3과 a4가 별개의 객체를 가리키고 있는 것을 볼 수 있습니다. 이 말은 a4.set_x(4)를 하더라도, a3의 필드 x에는 변화가 없다는 것을 의미합니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp14.png)
왜? 별개의 객체이기 때문입니다. 그리고, a4 객체의 필드값을 바꾸었어요. a3의 필드값을 그대로 a4에 복사했기 때문에, a3과 a4의 필드값은 별도의 메모리에 저장되어있을 겁니다. 아무런 영향이 없어요. 그런데, 아래의 경우는 이야기가 달라집니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp5.png)
b1 = B(3)입니다. 이 문장이 수행된 후 상황을 봅시다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp15.png)
위와 같은 상황이 됩니다. copy.copy(b1)만 했다면, 객체 B의 a 필드의 값만 복사될 겁니다. 객체 B의 a 필드의 값은 0x80입니다. 즉, 참조값만 복사된다는 의미입니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp16.png)
즉, 위와 같은 상황이 됩니다. 이 상황에서 b2.set_x(4)를 호출하면 어떻게 될까요? 클래스 B의 set_x 메소드는 self.a.set_x(4)를 호출합니다. 고로, 참조값 0x80이 가리키는 객체가 4로 수정되겠네요.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp17.png)
즉, 위와 같은 상황이 됩니다.
파이썬 copy deepcopy 차이점?
그래서, copy와 deepcopy 차이점이 무엇일까요? 새로운 객체를 생성하는 것은 같습니다. 차이점은, deepcopy는 재귀적으로 깊게 복사한다는 것입니다. copy가 복사 객체의 필드만 복사하는 것에 비해서요.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp6.png)
코드 4를 보겠습니다. 아까와 같이 객체를 하나 생성했어요. 다음에 deepcopy를 했어요.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp19.png)
그러면, 객체 b3, b4가 복사됩니다. 그 뿐만 아니라, 객체 안에 참조하고 있는 객체들도 모두 복사됩니다. 고로, b4.set_x(5)를 호출하더라도 객체 b4.a만 변하게 됩니다. 객체 b3.a와 b4.a는 내용이 복사된 다른 객체이기 때문입니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp20.png)
즉, 위와 같은 상황이 됩니다. 이 글에서 실습한 코드의 결과는 아래와 같습니다.
![](https://codingdog.pe.kr/wp-content/uploads/2024/02/deep_cp7.png)
이 글의 내용을 정리하면 아래와 같습니다.
- a = b는 참조값을 복사합니다.
- copy의 copy는 객체의 필드만 복사합니다.
- copy의 deepcopy는 객체의 객체 또한 재귀적으로 복사합니다.