다시 파이썬 포스팅을 시작하기로 마음먹고 medium에 재밌는 글이 있어 소개하고자 합니다.

https://towardsdatascience.com/no-and-list-are-different-in-python-8940530168b0

 

No, [] And list() Are Different In Python

Special Python literal constants make your program faster and more Pythonic

towardsdatascience.com

개인적으로 전에도 궁금했던 항목으로 []와 list()의 차이를 쉽게 설명하는 글입니다.

리스트 기호 또는 함수로 여러 변수를 배열로 만들어줍니다.

 

일단 시작하기에 앞서 [ ] 부호는 우리말로는 대괄호 영어로는 square brackets 으로 부릅니다. 검색할 때 [ ] 를 입력할 때 추가로 넣어주면 좀 더 검색이 잘 되겠지요~

(그리고 딕셔너리 { } 의 경우 한글로는 중괄호, 영어로는 curly brackets으로 부르고 튜플 ( ) 의 경우 우리는 괄호 영어로는 parentheses 로 부릅니다.)

 

[ ] 와 list()의 경우 분명히 두 개가 작동하는 방식이 다르다는 것에서부터 시작합니다.

빈 리스트를 만들때 li = [] 또는 li = list()를 이용하고 결과는 동일합니다.(사실 두번째 방법은 누가 실제로 이용하지 않긴합니다.ㅋㅋ)

 

위 포스트는 무엇보다도 두 방법의 속도 면에서 [ ] 가 월등히 빠르다는 것을 알려줍니다. 그리고 이를 측정하기 위해서 timeit 내장모듈을 사용합니다. (저는 처음 알았습니다.ㅎ)

 

import timeit

print(timeit.timeit('[]', number=10000000))
print(timeit.timeit('list()', number=10000000))

'''
결과
0.5182327
1.4793511000000001
'''

사용법은 timeit.timeit()를 이용하고 들어가는 인자의 경우 처음에는 원하는 수식 또는 함수를 문자열로 바꿔 넣어주고 뒤에 number의 경우 수행 회수입니다. 위와 같이 저는 천만번 수행하는 것으로 넣었는데 비교값을 정확히 확인하기 위해서입니다. 위 함수는 나중에도 쓸만 하겠네요. 수행하고자 하는 함수를 문자열로 넣어주는 것이 조금은 독특합니다.

 

결과를 보시듯이 빈 리스트를 만들 땐 []를 쓰는 것이 약 3배 가까이 빠르다는 것을 알 수 있습니다.

 

 

이제 각각의 방법이 내부에서 어떻게 작동하는지 알아봅니다. 이를 위해서 역시 dis란 이름의 내장함수를 이용합니다.

이를 위해서 배경 설명을 하자면 실제로 유저가 작성하는 각종 코드는 고차원적인 입력이고 실제 컴퓨터 내부에서는 제가 입력한 각종 코드를 다시 bytecode화 해서 수행한다고 합니다. 그리고 dis는 이러한 bytecode 명령을 알려줍니다.

 

from dis import dis

print(dis("[]"))
print(dis("list()"))

'''
  1           0 BUILD_LIST               0
              2 RETURN_VALUE
None
  1           0 LOAD_NAME                0 (list)
              2 CALL_FUNCTION            0
              4 RETURN_VALUE
'''

마찬가지로 dis()의 인자로 수행 명령하는 수식 또는 함수는 문자열로 묶어서 넣어줍니다.

 

일단 [ ]는 list( )에 비해서 단계가 한단계 적습니다.

그리고 각각의 명령을 살펴보면 다음과 같습니다.

 

[ ]

0 BUILD_LIST : [ ]를 바로 인지하고 LIST함수를 적용합니다.

2 RETURN_VALUE : 말 그대로 값을 Return합니다.

 

list

0 LOAD_NAME : list라는 이름을 존재하는 수많은 변수 중에서 찾습니다. 그리고 찾는 순서는

    Local Scope -> Enclosing Scope -> Global Scope -> Built-in Scope 라고 합니다. 

2 CALL_FUNCTION : 이제 list()라는 함수와 매칭이 되는것을 찾았을테니 함수를 수행합니다.

    만약에 매치하는 함수가 어디에도 없다면 그런이름을 가진 변수는 없다는 에러가 출력되겠지요!

4 RETURN_VALUE : 말 그대로 값을 Return합니다.

 

결국 [ ]와 list()는 애초에 작동 방식이 다르다는 것을 알 수 있습니다. 문자열 " " or ' ' 안에서가 아니라면 파이썬 인터프리터는 [ ] 를 만나면 바로 리스트등 관련 작업에 착수하지만 다른 알파벳을 만나면 다양한 scope안에서 검색을 하기 때문에 시간이 더 소요된다는 것을 알 수 있습니다.

 

 

그렇다면 여기서 급 궁금해 졌습니다. 위에서 파이썬에서는 어떤한 하나의 변수명을 검색할 경우 local scope (지역 범위)를 built-in scope (내장 범위) 보다 먼저 검색한다고 했는데 실제로 그러한지 앞서 설명한 timeit 모듈을 이용하여 확인해보고 싶어졌습니다.

 

일단 내장함수로 단순히 [ ]를 return하는 함수와 list()를 비교해 보려고 합니다.

 

그런데 일단 또 앞서 배운 dis 모듈을 이용해서 실제로 처리 절차는 두 함수가 동일한지부터 확인해 보겠습니다.

 

1. dis를 이용하여 직접 만든 함수 lis() 와 list()를 확인

2. timeit.timeit을 이용하여 두 함수의 수행속도를 확인

import timeit
from dis import dis

def lis():
    return []
    
print(dis("lis()"))
print(dis("list()"))

print(timeit.timeit('lis()', setup='from __main__ import lis', number=10000000))
print(timeit.timeit('list()', number=10000000))

'''
결과
y
  1           0 LOAD_NAME                0 (lis)
              2 CALL_FUNCTION            0
              4 RETURN_VALUE
None
  1           0 LOAD_NAME                0 (list)
              2 CALL_FUNCTION            0
              4 RETURN_VALUE
None
1.2204448
1.344584
'''

일단 두 함수의 작동 원리는 같다는 것을 확인하고 두번째로 나오는 결과값을 보면(수차례 돌려봤습니다.) list()가 제가 직접 만든 lis()함수보다 늦다는 것을 확인했습니다!

 

최근 몇개월간 리엑트 네이티브를 공부하며 느낀 점은 파이썬은 좀더 list 친화적이고 자바스크립트는 오브젝트 { }에 친화적이라는 얄팍한 생각을 해 봅니다. 

+ Recent posts