[Python] 얕은 복사 ? 깊은 복사? 🤔

sorzzzzy·2021년 11월 4일
0

TIL

목록 보기
5/36
post-thumbnail

알고리즘 문제를 풀며 잠깐 접했던 얕은복사, 깊은복사에 대해 자세히 알아보려고 한다!

1. mutable과 immutable 객체

>>> a = [1, 2, 3]
>>> id(a)
4393788808
>>> a[0] = 5
>>> a
[5, 2, 3]
>>> id(a)
4393788808

변수 a에 1,2,3을 원소로 가지는 리스트를 할당하고, id값을 확인해보자.
변수 a의 첫번째 원소를 변경해도 id값은 변함이 없는 것을 확인 할 수 있다!

>>> s= "abc"
>>> s
'abc'
>>> id(s)
4387454680
>>> s[0]
'a'
>>> s[0] = 's'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = 'def'
>>> s
'def'
>>> id(s)
4388970768

str 타입은 ìmmutable 이다.
s 변수의 첫번째 글자를 변경하려고 하면, 에러가 발생한다.
만약 s에 다른 값을 할당하면, id가 변경된다.
재할당은 애초에 변수를 다시할당하는 것이므로 mutableimmutable과는 다른 문제이며, list 또한 값을 재할당하면 id 가 변경된다.



2. 변수 간 대입

2-1. mutable한 객체의 변수 간 대입

  • list의 얕은 복사를 확인해보자.
  • ba를 할당하면 값이 할당되는 것이 아니라 같은 메모리 주소를 바라보게 된다.
  • b를 변경하면 a의 값도 함께 변경된다.
  • mutable한 다른 객체 또한 똑같은 현상이 나타난다.
>>> a = [1, 2, 3]
>>> b = a # shallow copy
>>> b[0]= 5
>>> a
[5, 2, 3]
>>> b
[5, 2, 3]
>>> id(a)
4396179528
>>> id(b)
4396179528

2-2. immutable한 객체의 변수간 대입

  • 문자열 타입을 예로 얕은 복사를 실습해 보자.
  • list 와 같이, ba에 할당하면 같은 메모리 주소를 가지게 된다.
  • 그러나 b의 값을 변경하면, 재할당이 이루어지면서 메모리 주소가 변경된다.
  • 따라서 ab는 결과적으로 다른 값을 가지게 된다.
>>> a = "abc"
>>> b = a
>>> a
'abc'
>>> b
'abc'
>>> id(a)
4387454680
>>> id(b)
4387454680
>>> b = "abcd"
>>> a
'abc'
>>> b
'abcd'
>>> id(a)
4387454680
>>> id(b)
4396456400


3. 얕은 복사

>>> a = [1,2,3]
>>> b = a[:]
>>> id(a)
4396179528
>>> id(b)
4393788808
>>> a == b
True
>>> a is b
False
>>> b[0] = 5
>>> a
[1, 2, 3]
>>> b
[5, 2, 3]

list를 슬라이싱해 새로운 값을 할당했다.
슬라이싱을 통해 ab로 할당하면, 새로운 id가 부여되고 서로 영향을 받지 않는다.

그러나 이것 또한 얕은 복사이다 ❗️


문제가 되는 경우 1) 리스트안에 리스트 mutable 객체 안에 mutable 객체인 경우

>>> a = [[1,2], [3,4]]
>>> b = a[:]
>>> id(a)
4395624328
>>> id(b)
4396179592
>>> id(a[0])
4396116040
>>> id(b[0])
4396116040

➡️ id(a) 값과 id(b) 값은 다르게 되었지만, 그 내부의 객체 id(a[0])id(b[0])은 같은 주소를 바라보고 있다.


문제가 되는 경우 2) 재할당하는 경우

>>> a[0] = [8,9]
>>> a
[[8, 9], [3, 4]]
>>> b
[[1, 2], [3, 4]]
>>> id(a[0])
4393788808
>>> id(b[0])
4396116040

겉으로 봐서는 메모리 주소도 변경되고 문제가 없어 보이지만,

>>> a[1].append(5)
>>> a
[[8, 9], [3, 4, 5]]
>>> b
[[1, 2], [3, 4, 5]]
>>> id(a[1])
4396389896
>>> id(b[1])
4396389896

➡️ a[1]의 값을 변경하면 b[1]도 함께 변경된다.

📌 copy모듈의 copy()메소드 또한 얕은 복사이다.



4. 깊은 복사

깊은 복사란, 내부의 객체들까지 모두 새롭게 복사되는 것이다.
copy.deepcopy() 메소드를 활용하면 된다!

>>> import copy
>>> a = [[1,2],[3,4]]
>>> b = copy.deepcopy(a)
>>> a[1].append(5)
>>> a
[[1, 2], [3, 4, 5]]
>>> b
[[1, 2], [3, 4]]

📌 참고자료

profile
Backend Developer

0개의 댓글