파이썬 리스트 복사 어떻게 할까?
Photo by Zdeněk Macháček on Unsplash
오늘은 상당히 기초적이면서도 쉽게 실수 할 수 있는 부분을 다뤄보고자 한다. 바로 나를 포함한 초보자들이 실수할 수 있는 파이썬 리스트를 다른 리스트에 복사하는 방법이다.
그냥 새로운 변수에 정의해주면 되는거 아냐 🤔❓
>>> list1 = [1, 2, 3, 4]
>>> list2 = list1
>>> print(list1)
[1, 2, 3, 4]
>>> print(list2)
[1, 2, 3, 4]
위 예제의 결과만 보면 파이썬이 워낙 간편하다보니 별 의심없이 잘 복사됐다고 생각할 수 있다. 하지만 정확히 말하면 list2
는 list1
의 메모리 주소값을 복사한 것이다. 즉, 같은 메모리를 참조하기 때문에 list1
이 수정되면 list2
도 동시에 수정된다. 하지만 이것을 간과하고 열심히 코드를 짜다보면 나중에 깊은 오류의 구렁텅이에 빠질 수 있다. 혹시나 그런 오류에 빠진 사람들이 이 글을 보고 도움이 되었으면 좋겠다 :)
아니 이게 왜 안돼 🐥❓
>>> list1 = [1, 2, 3, 4]
>>> list2 = list1
>>> print('list1 :', list1, '/ id :', id(list1))
list1 : [1, 2, 3, 4] / id : 4552076160
>>> print('list2 :', list2, '/ id :', id(list2))
list2 : [1, 2, 3, 4] / id : 4552076160
>>> list1[0] = 11
>>> print('list1 :', list1)
list1 : [11, 2, 3, 4]
>>> print('list2 :', list2)
list2 : [11, 2, 3, 4]
파이썬 객체의 메모리 주소를 확인하는 id()
함수를 이용해 list1
와 list2
의 주소값을 확인해보면 두 리스트 모두 4552076160로 같은 주소값을 가지는 것을 확인할 수 있다. 엄밀히 말해서 list2는 list1의 분신과 같은 존재이고, 일반적으로 우리가 원하는 복사는 이뤄지지 않은 것이다.
그럼 어떻게 해야 하는데 😲❓
앞서 살펴본 문제점과 같이 우리가 원하는 복사가 이뤄지지 않았던 이유는 list1
와 list2
두 변수가 같은 메모리를 참조하기 때문이다. 결국 우리가 원하는 복사가 이뤄지기 위해서는 list1
와 list2
이 서로 다른 메모리를 참조하도록 해주면 된다. 파이썬 리스트를 다른 리스트에 복사하는 방법은 4가지가 있다.
1) 슬라이싱
>>> list1 = [1, 2, 3, 4]
>>> list2 = list1[:]
시작점과 끝점을 생략한 슬라이싱은 리스트의 모든 요소를 뜻한다. 슬라이싱을 통해 변수를 정의하면 파이썬은 새로운 객체를 만든다.
2) list() 함수
>>> list1 = [1, 2, 3, 4]
>>> list2 = list(list1)
파이썬 내장함수 중에는 iterable한 객체를 리스트 객체로 변환해주는 list()
함수가 있다. 이 함수를 이용해 복사하고자 하는 리스트 객체를 다시 재선언 한다.
3) copy() 메소드
>>> list1 = [1, 2, 3, 4]
>>> list2 = list1.copy()
Python3 부터 리스트를 다른 리스트에 복사하는 기능인 copy()
메소드가 추가되었다. 가독성을 위한 코드라면 이 방법을 사용하는 것을 권장한다.
4) 리스트 연산
>>> list1 = [1, 2, 3, 4]
>>> list2 = [] + list1
리스트 덧셈연산을 이용해 새로운 빈 리스트에 list1
의 요소들을 더한다. 새로운 리스트 객체에 list1
의 요소들이 더해져 결과적으로 우리가 원하는 복사가 이뤄진다.
검증
>>> def copy_element(method):
list1 = [1, 2, 3, 4]
if method == 1:
list2 = list1[:]
elif method == 2:
list2 = list(list1)
elif method == 3:
list2 = list1.copy()
elif method == 4:
list2 = [] + list1
print(f'방법 {method}')
print('list1 :', list1, '/ id :', id(list1))
print('list2 :', list2, '/ id :', id(list2))
list1[0] = 11
print('list1 :', list1)
print('list2 :', list2)
print('')
>>> [copy_element(method) for method in range(1, 5)]
방법 1
list1 : [1, 2, 3, 4] / id : 4552075648
list2 : [1, 2, 3, 4] / id : 4552076096
list1 : [11, 2, 3, 4]
list2 : [1, 2, 3, 4]
방법 2
list1 : [1, 2, 3, 4] / id : 4552076096
list2 : [1, 2, 3, 4] / id : 4552164288
list1 : [11, 2, 3, 4]
list2 : [1, 2, 3, 4]
방법 3
list1 : [1, 2, 3, 4] / id : 4552164288
list2 : [1, 2, 3, 4] / id : 4552076096
list1 : [11, 2, 3, 4]
list2 : [1, 2, 3, 4]
방법 4
list1 : [1, 2, 3, 4] / id : 4552076096
list2 : [1, 2, 3, 4] / id : 4552075648
list1 : [11, 2, 3, 4]
list2 : [1, 2, 3, 4]
각자의 방법 모두 서로 다른 리스트 객체에 값이 할당되며, list1의 요소에 수정이 일어나도 list2 요소에 영향을 끼치지 않는 독립적인 개체임을 확인할 수 있다.
댓글 남기기