백준 풀이를 하다 리스트를 깊은 복사할 때, deepcopy()를 사용한 코드가 slicing을 사용한 코드보다 7배 이상의 시간이 걸린 것을 확인하고 정리해봐야겠다는 생각이 들었습니다!
가뜩이나 느린 파이썬에서 시간이 이렇게 감소한다면 충분히 공부해 볼 가치가 있죠 😤
파이썬 시간을 단축시키는 방법으로는 입출력 시간을 단축시키는 것도 있습니다! 다음 글에 정리해두었습니다
📌 https://codesyun.tistory.com/178
깊은 복사 / 얕은 복사에 대해서도 다시 짚고 넘어가며 리스트 복사 방법에 대해 알아보겠습니다 🔥
복사 (Copy)
알고리즘 풀이를 하다보면 원본 리스트를 보존하기 위해 리스트를 복사해야 할 필요를 느끼곤 합니다
복사에 대해 제대로 알지 못한 채로 함부로 복사하면, 원본 객체가 변경되어 큰 문제가 생길 수 있습니다
파이썬에서 복사는 '='연산자와 copy 모듈의 copy(), deepcopy()와 slicing을 통해 수행할 수 있습니다
> 얕은 복사 (Shallow Copy)
: 원본 객체의 주소 값을 복사하는 것
> 깊은 복사 (Deep Copy)
: 참조 주소 값이 아닌 참조된 객체 자체를 복사하는 것
> '=' 연산자
import copy
origin_list = [1, 2, 3]
copy_list_a = origin_list # '=' operator
origin_list = [1, 2, 3]
copy_list = origin_list
print(id(origin_list)) # 1713539575424
print(id(copy_list)) # 1713539575424
print(origin_list) # [1, 2, 3]
print(copy_list) # [1, 2, 3]
copy_list[0] = 5
print(origin_list) # [5, 2, 3]
print(copy_list) # [5, 2, 3]
- 원본 리스트와 복사된 리스트가 같은 주소를 가지고 같은 객체를 가리키고 있다
- 따라서 복사된 리스트를 변경하면 원본 리스트 또한 변경된다
- 불변형(immutable) 객체에서는 복사한 객체에 데이터를 변경해도 원본 객체에 영향이 없지만, 리스트와 같은 변형(mutable) 객체에서는 복사한 객체의 변경이 원본 객체에도 영향을 미친다
> copy 모듈의 copy() 함수 / List Slicing [:]
import copy
origin_list = [1, 2, 3]
copy_list_a = copy.copy(origin_list) # copy() function of copy module
copy_list_b = origin_list[:] # list slicing
import copy
origin_list = [1, 2, 3]
copy_list = copy.copy(origin_list)
print(id(origin_list)) # 4378158400
print(id(copy_list)) # 4378158272
print(origin_list) # [1, 2, 3]
print(copy_list) # [1, 2, 3]
copy_list[0] = 5
print(origin_list) # [5, 2, 3]
print(copy_list) # [5, 2, 3]
- 원본 리스트와 복사된 리스트는 각기 다른 객체이다
- 따라서 복사된 리스트를 변경하여도 원본 리스트에는 변화가 없다
- 하지만 다음과 같이 이차원 배열을 복사하면, 각 요소인 배열을 변경할 경우 원본에 영향을 미친다
origin_list = [[1, 1], [2, 2], [3, 3]]
copy_list = origin_list[:]
print(origin_list) # [[1, 1], [2, 2], [3, 3]]
print(copy_list) # [[1, 1], [2, 2], [3, 3]]
copy_list[1][1] = 99
print(origin_list) # [[1, 1], [2, 99], [3, 3]]
print(copy_list) # [[1, 1], [2, 99], [3, 3]]
> copy 모듈의 deepcopy() 함수
- 다차원 배열을 완전히 복사하기 위해선 deepcopy 함수를 사용해야 한다
. 리스트 슬라이싱을 응용하여 다차원배열을 완전 복사하는 것 또한 가능하다
import copy
origin_list = [1, 2, 3]
copy_list_a = copy.deepcopy(origin_list) # deepcopy() function of copy module
import copy
origin_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# deepcopy()
copy_list_a = copy.deepcopy(origin_list)
# list slicing
copy_list_b = [item[:] for item in origin_list]
- 다차원 배열 복사의 방법별 처리 속도
- 10.59 sec (105.9 µs/itn) - copy.deepcopy(old_list)
- 10.16 sec (101.6 µs/itn) - pure Python Copy() method copying classes with deepcopy
- 1.488 sec (14.88 µs/itn) - pure Python Copy() method not copying classes (only dicts/lists/tuples)
- 0.325 sec (3.25 µs/itn) - for item in old_list: new_list.append(item)
- 0.217 sec (2.17 µs/itn) - [i for i in old_list] (a list comprehension)
- 0.186 sec (1.86 µs/itn) - copy.copy(old_list)
- 0.075 sec (0.75 µs/itn) - list(old_list)
- 0.053 sec (0.53 µs/itn) - new_list = []; new_list.extend(old_list)
- 0.039 sec (0.39 µs/itn) - old_list[:] (list slicing)
- list slicing이 가장 빠르고 deepcopy가 가장 느린 것을 확인할 수 있습니다!
'Programming > Python' 카테고리의 다른 글
[Python] 파이썬 sys.stdin.readline() 입력 받기 : 시간 초과 해결, 입출력 속도 개선 (0) | 2021.07.21 |
---|---|
[Python] 파이썬 리스트 : 선언, 연산자, 요소 추가, 요소 제거, in / not in (0) | 2021.07.20 |
[Python] 파이썬 조건문 : if, else, elif 조건문, 조건문 내부를 구현하지 않았을 때 (0) | 2021.07.20 |
[Python] 파이썬 자료형 (3) : Boolean(불) 자료형, 비교 연산자, 논리 연산자 (0) | 2021.07.20 |
[Python] 파이썬 자료형 (2) : 문자열 입력, 문자열 관련 함수 (0) | 2021.07.17 |