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