[Python] copy 모듈 존재의 이유
Python의 'is' 커맨드를 설명하는 과정에서 Python의 대입은 레퍼런스 대입이라고 설명한 적이 있다. 그리고 이 레퍼런스 대입 시의 문제를 해결하기 위해 copy 모듈이 존재한다. 왜 copy 모듈이 필요한걸까.
레퍼런스 문제는 리스트에서도 여전히 발생한다.
이런 리스트 레퍼런스로 인한 문제는 리스트를 복사함으로써 해결 할 수 있다.
여기서 사용한
복사하는 방법을 알아냈지만 여전히 레퍼런스 문제가 발생하는 경우가 있다. 중첩(nested)된 리스트의 경우 리스트 안에 리스트가 존재하는 형태인데 이 경우를 시험해 보면...
copy.copy의 경우도 동일하다.
그렇다면 이런 문제를 회피하기 위해
... 그런데 너무 귀찮다!! ...
다행히도 해법을 제공해 주고 있으니 걱정할 건 없다.
물론 deepcopy도 모든 타입에 이용이 가능하다.
개인적으론 고민하지 않고 공유메모리 형태로 사용하는 리스트의 데이터는 무조건 deepcopy로 복사해 버린다. 워낙 관련 문제를 많이 겪었더니...;;;
사족. 스크립트 언어에서 레퍼런스(포인터) 개념을 이용한다는 것은 굉장히 슬픈 일이다. 괜히 생각을 복잡하게 만들어야 하니까. 이 모든 것이 성능 때문에 쓰는 개념이라는 것을 이해해야 하기 때문에 더욱 슬퍼진다.
레퍼런스 문제는 리스트에서도 여전히 발생한다.
>>> a = [1, 2, 3] >>> b = a >>> a [1, 2, 3] >>> b [1, 2, 3] >>> a[1] = -99 >>> a [1, -99, 3] >>> b [1, -99, 3]b가 a의 레퍼런스를 가져간 만큼 a가 바뀌면 b도 바뀐다. a 와 b 는 둘 다 동일한 메모리를 가리키고 있다.
이런 리스트 레퍼런스로 인한 문제는 리스트를 복사함으로써 해결 할 수 있다.
>>> a = [1, 2, 3] >>> b = a[:] >>> a[2] = -98 >>> b [1, 2, 3]이제 a와 b는 다른 메모리를 가리키고 있게 되었다.
여기서 사용한
[:]
문법은 copy 모듈의 copy를 이용해서 동일하게 동작하게 할 수 있다.>>> a = [1, 2, 3] >>> import copy >>> b = copy.copy(a) >>> b [1, 2, 3] >>> a[0] = 20 >>> b [1, 2, 3]copy.copy는 shallow copy라고 부른다. 어쨌든 결과적으로 리스트가 동일하게 복사되었다.
[:]
문법을 이용해 복사하는 것과 다른 점은, copy.copy는 모든 타입의 변수를 다 복사한다는 점이다. [:]
는 리스트에만 사용할 수 있으니까.복사하는 방법을 알아냈지만 여전히 레퍼런스 문제가 발생하는 경우가 있다. 중첩(nested)된 리스트의 경우 리스트 안에 리스트가 존재하는 형태인데 이 경우를 시험해 보면...
>>> a = [1, 2, 3] >>> b = [4, a, 5] >>> b [4, [1, 2, 3], 5] >>> c = b[:] >>> c [4, [1, 2, 3], 5] >>> a[0] = 100 >>> c [4, [100, 2, 3], 5] >>> b [4, [100, 2, 3], 5]b 안에서 a를 참조하고 있다. c는 b의 사본을 가져갔음에도 a에 영향을 받고 있다. 여기서 파악 가능한 건
[:]
로 리스트를 복사하는 건 nested list까지는 적용이 되지 않는다는 점이다.copy.copy의 경우도 동일하다.
>>> a = [1, 2, 3] >>> b = [4, a, 5] >>> c = copy.copy(b) >>> c [4, [1, 2, 3], 5] >>> a[0] = 50 >>> c [4, [50, 2, 3], 5]shallow copy도 1차원적인 복사만을 한다는 것을 알 수 있다.
그렇다면 이런 문제를 회피하기 위해
[:]
문법이나 copy.copy를 리스트 안의 모든 리스트를 돌아다니며 일일이 해 주면 해결할 수 있을 것이다.... 그런데 너무 귀찮다!! ...
다행히도 해법을 제공해 주고 있으니 걱정할 건 없다.
>>> a = [1, 2, 3] >>> b = [4, a, 5] >>> import copy >>> c = copy.deepcopy(b) >>> c [4, [1, 2, 3], 5] >>> a[0] = -999 >>> c [4, [1, 2, 3], 5] >>> b [4, [-999, 2, 3], 5]copy.deepcopy는 이름 그대로 deep copy이다. 특히 nested list도 완벽하게 복사해 내는 등 거의 완벽한 복사를 자랑하는 모듈이다.
물론 deepcopy도 모든 타입에 이용이 가능하다.
개인적으론 고민하지 않고 공유메모리 형태로 사용하는 리스트의 데이터는 무조건 deepcopy로 복사해 버린다. 워낙 관련 문제를 많이 겪었더니...;;;
사족. 스크립트 언어에서 레퍼런스(포인터) 개념을 이용한다는 것은 굉장히 슬픈 일이다. 괜히 생각을 복잡하게 만들어야 하니까. 이 모든 것이 성능 때문에 쓰는 개념이라는 것을 이해해야 하기 때문에 더욱 슬퍼진다.
댓글