본문 바로가기

프로그래머/Python

[널널한 교수의 고급 파이썬] 04-4 append()와 +연산을 통한 리바인딩의 성능 비교

04-4 append()와 +연산을 통한 리바인딩의 성능 비교

리스트 요소의 추가

a = [1, 2, 3, 4]    # 리스트 객체 생성
a.append(5)         # 리스트 객체의 변경(mutating)

리스트의 덧셈 연산과 재할당

a = [1, 2, 3, 4]    # 리스트 객체 생성
a = a + [5]         # 리스트 객체의 재바인딩(rebinding)
# 리스트 자료형은 가변(mutable)
# -> 객체의 니용이 바뀌어도 id는 안 바뀜
a = [1, 2, 3, 4]
id(a)
a.append(5)
id(a)

# a 객체는 다시 바인딩 된다
a = [1, 2, 3, 4]
id(a)
id(a[0])
a = a + [5]
id(a)
id(a[0])

이것을 알아야 하는 이유

  • 리스트 객체는 변경가능 객체
    • int형, tuple형, str형 객체는 변경 불가능(immuatble) 객체
  • 리스트의 append() 메소드는 객체의 내용을 변경시킴
  • 리스트의 + 연산은 객체로 복사해서 다시 바인딩(리바인딩) 함
  • 리바인딩은 시간이 많이 걸린다
  • 리스트 객체의 append()는 상대적으로 빨리 수행된다

10만개의 데이터를 삽입하는데 걸리는 시간

import time

start_time = time.time()
a = []
for i in range(100000):
    a.append(i)

end_time = time.time()
t1 = end_time - start_time  # 0.014

# 매번 객체를 리바인딩하기 때문에 속도가 느리며,
# 가비지 메모리도 발생함
start_time = time.time()
b = []
for i in range(100000):
    b = b + [i]

end_time = time.time()
t2 = end_time - start_time  # 22.03

# list(range(100000))을 사용함
start_time = time.time()
c = list(range(100000))
end_time = time.time()
t3 = end_time - start_time  # 0.004

# numpy의 ndarray 객체
# 동일 자료형의 객체를 이웃한 메모리 위치에 삽입
# C언어의 배열과 유사하다
import numpy as np

start_time = time.time()
d = np.arange(100000)
end_time = time.time()
t4 = end_time - start_time  # 0.001

정리

  • 리바인딩은 시간이 많이 소요
  • 그래서 성능이 좋지 않음
    • 파이썬은 느리다고 불평하는 경우가 이 경우
  • 하지만 numpy를 사용하면 C와 비슷한 속도를 얻을 수 있다

라이브러리 최적화

  • 파이썬의 동적할당 자체는 느리지만 최적화된 라이브러리들이 많다
  • 파이썬은 느리다?
    • 그렇다. 또한 그렇지 않다!
    • 최적화된 라이브러리를 사용하면 좋은 성능을 보인다